2020-01-01 21:29:24 +01:00
|
|
|
#include "Entity.h"
|
|
|
|
#include "Game.h"
|
|
|
|
#include "Map.h"
|
|
|
|
#include "UtilityClass.h"
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
bool entityclass::checktowerspikes(int t)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("checktowerspikes() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
tempx = entities[t].xp + entities[t].cx;
|
|
|
|
tempy = entities[t].yp + entities[t].cy;
|
|
|
|
tempw = entities[t].w;
|
|
|
|
temph = entities[t].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
|
|
|
|
tempx = getgridpoint(temprect.x);
|
|
|
|
tempy = getgridpoint(temprect.y);
|
|
|
|
tempw = getgridpoint(temprect.x + temprect.w - 1);
|
|
|
|
temph = getgridpoint(temprect.y + temprect.h - 1);
|
|
|
|
if (map.spikecollide(tempx, tempy)) return true;
|
|
|
|
if (map.spikecollide(tempw, tempy)) return true;
|
|
|
|
if (map.spikecollide(tempx, temph)) return true;
|
|
|
|
if (map.spikecollide(tempw, temph)) return true;
|
|
|
|
if (temprect.h >= 12)
|
|
|
|
{
|
|
|
|
tpy1 = getgridpoint(temprect.y + 6);
|
|
|
|
if (map.spikecollide(tempx, tpy1)) return true;
|
|
|
|
if (map.spikecollide(tempw, tpy1)) return true;
|
|
|
|
if (temprect.h >= 18)
|
|
|
|
{
|
|
|
|
tpy1 = getgridpoint(temprect.y + 12);
|
|
|
|
if (map.spikecollide(tempx, tpy1)) return true;
|
|
|
|
if (map.spikecollide(tempw, tpy1)) return true;
|
|
|
|
if (temprect.h >= 24)
|
|
|
|
{
|
|
|
|
tpy1 = getgridpoint(temprect.y + 18);
|
|
|
|
if (map.spikecollide(tempx, tpy1)) return true;
|
|
|
|
if (map.spikecollide(tempw, tpy1)) return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::init()
|
|
|
|
{
|
2020-01-25 02:26:00 +01:00
|
|
|
skipblocks = false;
|
2020-01-01 21:29:24 +01:00
|
|
|
skipdirblocks = false;
|
|
|
|
platformtile = 0;
|
|
|
|
customplatformtile=0;
|
|
|
|
vertplatforms = false;
|
|
|
|
horplatforms = false;
|
|
|
|
|
|
|
|
nearelephant = false;
|
|
|
|
upsetmode = false;
|
|
|
|
upset = 0;
|
|
|
|
|
|
|
|
customenemy=0;
|
|
|
|
customwarpmode=false; customwarpmodevon=false; customwarpmodehon=false;
|
|
|
|
trophytext = 0 ;
|
2020-04-30 01:54:36 +02:00
|
|
|
oldtrophytext = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
trophytype = 0;
|
|
|
|
altstates = 0;
|
|
|
|
|
|
|
|
|
2020-07-03 03:10:52 +02:00
|
|
|
SDL_memset(customcrewmoods, true, sizeof(customcrewmoods));
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-07-03 03:22:19 +02:00
|
|
|
resetallflags();
|
2020-01-12 12:28:34 +01:00
|
|
|
collect.resize(100);
|
|
|
|
customcollect.resize(100);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::resetallflags()
|
|
|
|
{
|
2020-07-03 03:22:19 +02:00
|
|
|
SDL_memset(flags, false, sizeof(flags));
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int entityclass::swncolour( int t )
|
|
|
|
{
|
|
|
|
//given colour t, return colour in setcol
|
|
|
|
if (t == 0) return 11;
|
|
|
|
if (t == 1) return 6;
|
|
|
|
if (t == 2) return 8;
|
|
|
|
if (t == 3) return 12;
|
|
|
|
if (t == 4) return 9;
|
|
|
|
if (t == 5) return 7;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::swnenemiescol( int t )
|
|
|
|
{
|
|
|
|
//change the colour of all SWN enemies to the current one
|
2020-04-03 22:50:16 +02:00
|
|
|
for (size_t i = 0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[i].type == 23)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].colour = swncolour(t);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
void entityclass::gravcreate( int ypos, int dir, int xoff /*= 0*/, int yoff /*= 0*/ )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (dir == 0)
|
|
|
|
{
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(-150 - xoff, 58 + (ypos * 20)+yoff, 23, 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(320+150 + xoff, 58 + (ypos * 20)+yoff, 23, 1, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
void entityclass::generateswnwave( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//generate a wave for the SWN game
|
|
|
|
if(game.swndelay<=0)
|
|
|
|
{
|
|
|
|
if (t == 0) //game 0, survive for 30 seconds
|
|
|
|
{
|
|
|
|
switch(game.swnstate)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
//Decide on a wave here
|
|
|
|
//default case
|
|
|
|
game.swnstate = 1;
|
|
|
|
game.swndelay = 5;
|
|
|
|
|
|
|
|
if (game.swntimer <= 150) //less than 5 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 9;
|
|
|
|
game.swndelay = 8;
|
|
|
|
}
|
|
|
|
else if (game.swntimer <= 300) //less than 10 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 6;
|
|
|
|
game.swndelay = 12;
|
|
|
|
}
|
|
|
|
else if (game.swntimer <= 360) //less than 12 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 5+game.swnstate2;
|
|
|
|
game.swndelay = 15;
|
|
|
|
}
|
|
|
|
else if (game.swntimer <= 420) //less than 14 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 7+game.swnstate2;
|
|
|
|
game.swndelay = 15;
|
|
|
|
}
|
|
|
|
else if (game.swntimer <= 480) //less than 16 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 5+game.swnstate2;
|
|
|
|
game.swndelay = 15;
|
|
|
|
}
|
|
|
|
else if (game.swntimer <= 540) //less than 18 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 7+game.swnstate2;
|
|
|
|
game.swndelay = 15;
|
|
|
|
}
|
|
|
|
else if (game.swntimer <= 600) //less than 20 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 5+game.swnstate2;
|
|
|
|
game.swndelay = 15;
|
|
|
|
}
|
|
|
|
else if (game.swntimer <= 900) //less than 30 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 4;
|
|
|
|
game.swndelay = 20;
|
|
|
|
}
|
|
|
|
else if (game.swntimer <= 1050) //less than 35 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 3;
|
|
|
|
game.swndelay = 10;
|
|
|
|
}
|
|
|
|
else if (game.swntimer <= 1200) //less than 40 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 3;
|
|
|
|
game.swndelay = 20;
|
|
|
|
}
|
|
|
|
else if (game.swntimer <= 1500) //less than 50 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 2;
|
|
|
|
game.swndelay = 10;
|
|
|
|
}
|
|
|
|
else if (game.swntimer <= 1650) //less than 55 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 1;
|
|
|
|
game.swndelay = 15;
|
|
|
|
}
|
|
|
|
else if (game.swntimer <= 1800) //less than 60 seconds
|
|
|
|
{
|
|
|
|
game.swnstate = 1;
|
|
|
|
game.swndelay = 25;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (game.deathcounts - game.swndeaths > 7) game.swndelay += 2;
|
|
|
|
if (game.deathcounts - game.swndeaths > 15) game.swndelay += 2;
|
|
|
|
if (game.deathcounts - game.swndeaths > 25) game.swndelay += 4;
|
|
|
|
break;
|
|
|
|
case 1:
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(-150, 58 + (int(fRandom() * 6) * 20), 23, 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 0; //return to decision state
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if(game.swnstate3==0)
|
|
|
|
{
|
|
|
|
game.swnstate2++;
|
|
|
|
if (game.swnstate2 >= 6)
|
|
|
|
{
|
|
|
|
game.swnstate3 = 1;
|
|
|
|
game.swnstate2--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate2--;
|
|
|
|
if (game.swnstate2 < 0)
|
|
|
|
{
|
|
|
|
game.swnstate3 = 0;
|
|
|
|
game.swnstate2++;
|
|
|
|
}
|
|
|
|
}
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(-150, 58 + (int(game.swnstate2) * 20), 23, 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 0; //return to decision state
|
|
|
|
break;
|
|
|
|
case 3:
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(320+150, 58 + (int(fRandom() * 6) * 20), 23, 1, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 0; //return to decision state
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
//left and right compliments
|
|
|
|
game.swnstate2 = int(fRandom() * 6);
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(-150, 58 + (game.swnstate2 * 20), 23, 0, 0);
|
|
|
|
createentity(320+150, 58 + ((5-game.swnstate2) * 20), 23, 1, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 0; //return to decision state
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
//Top and bottom
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(-150, 58, 23, 0, 0);
|
|
|
|
createentity(-150, 58 + (5 * 20), 23, 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 0; //return to decision state
|
|
|
|
game.swnstate2 = 1;
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
//Middle
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(-150, 58 + (2 * 20), 23, 0, 0);
|
|
|
|
createentity(-150, 58 + (3 * 20), 23, 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 0; //return to decision state
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
//Top and bottom
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(320+150, 58, 23, 1, 0);
|
|
|
|
createentity(320+150, 58 + (5 * 20), 23, 1, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 0; //return to decision state
|
|
|
|
game.swnstate2 = 1;
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
//Middle
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(320+150, 58 + (2 * 20), 23, 1, 0);
|
|
|
|
createentity(320+150, 58 + (3 * 20), 23, 1, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 0; //return to decision state
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
break;
|
|
|
|
case 9:
|
|
|
|
if(game.swnstate3==0)
|
|
|
|
{
|
|
|
|
game.swnstate2++;
|
|
|
|
if (game.swnstate2 >= 6)
|
|
|
|
{
|
|
|
|
game.swnstate3 = 1;
|
|
|
|
game.swnstate2--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate2--;
|
|
|
|
if (game.swnstate2 < 0)
|
|
|
|
{
|
|
|
|
game.swnstate3 = 0;
|
|
|
|
game.swnstate2++;
|
|
|
|
}
|
|
|
|
}
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(320 + 150, 58 + (int(game.swnstate2) * 20), 23, 1, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 0; //return to decision state
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (t == 1)
|
|
|
|
{
|
|
|
|
//Game 2, super gravitron
|
|
|
|
switch(game.swnstate)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
//Choose either simple or filler
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
game.swnstate3 = 0;
|
|
|
|
game.swnstate4 = 0;
|
|
|
|
|
|
|
|
game.swnstate2 = int(fRandom() * 100);
|
|
|
|
if (game.swnstate2 < 25)
|
|
|
|
{
|
|
|
|
//simple
|
|
|
|
game.swnstate = 2;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//filler
|
|
|
|
game.swnstate = 4;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
//complex chain
|
|
|
|
game.swnstate2 = int(fRandom() * 8);
|
|
|
|
if (game.swnstate2 == 0)
|
|
|
|
{
|
|
|
|
game.swnstate = 10;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 1)
|
|
|
|
{
|
|
|
|
game.swnstate = 12;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 2)
|
|
|
|
{
|
|
|
|
game.swnstate = 14;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 3)
|
|
|
|
{
|
|
|
|
game.swnstate = 20;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 4)
|
|
|
|
{
|
|
|
|
game.swnstate = 21;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 5)
|
|
|
|
{
|
|
|
|
game.swnstate = 22;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 6)
|
|
|
|
{
|
|
|
|
game.swnstate = 22;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 7)
|
|
|
|
{
|
|
|
|
game.swnstate = 14;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
//simple chain
|
|
|
|
game.swnstate2 = int(fRandom() * 6);
|
|
|
|
if (game.swnstate2 == 0)
|
|
|
|
{
|
|
|
|
game.swnstate = 23;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 1)
|
|
|
|
{
|
|
|
|
game.swnstate = 24;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 2)
|
|
|
|
{
|
|
|
|
game.swnstate = 25;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 3)
|
|
|
|
{
|
|
|
|
game.swnstate = 26;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 4)
|
|
|
|
{
|
|
|
|
game.swnstate = 27;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 5)
|
|
|
|
{
|
|
|
|
game.swnstate = 14;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
//Choose a major action
|
|
|
|
game.swnstate2 = int(fRandom() * 100);
|
|
|
|
if (game.swnstate2 < 25)
|
|
|
|
{
|
|
|
|
//complex
|
|
|
|
game.swnstate = 1;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//simple
|
|
|
|
game.swnstate = 2;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
//filler chain
|
|
|
|
game.swnstate2 = int(fRandom() * 6);
|
|
|
|
if (game.swnstate2 == 0)
|
|
|
|
{
|
|
|
|
game.swnstate = 28;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 1)
|
|
|
|
{
|
|
|
|
game.swnstate = 29;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 2)
|
|
|
|
{
|
|
|
|
game.swnstate = 28;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 3)
|
|
|
|
{
|
|
|
|
game.swnstate = 29;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 4)
|
|
|
|
{
|
|
|
|
game.swnstate = 30;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
else if (game.swnstate2 == 5)
|
|
|
|
{
|
|
|
|
game.swnstate = 31;
|
|
|
|
game.swndelay = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
break;
|
|
|
|
case 10:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(0, 0);
|
|
|
|
gravcreate(1, 0);
|
|
|
|
gravcreate(2, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate++;
|
|
|
|
game.swndelay = 10; //return to decision state
|
|
|
|
break;
|
|
|
|
case 11:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(3, 0);
|
|
|
|
gravcreate(4, 0);
|
|
|
|
gravcreate(5, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate2++;
|
|
|
|
if(game.swnstate2==3)
|
|
|
|
{
|
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 30; //return to decision state
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate--;
|
|
|
|
game.swndelay = 10; //return to decision state
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 12:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(0, 1);
|
|
|
|
gravcreate(1, 1);
|
|
|
|
gravcreate(2, 1);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate++;
|
|
|
|
game.swndelay = 10; //return to decision state
|
|
|
|
break;
|
|
|
|
case 13:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(3, 1);
|
|
|
|
gravcreate(4, 1);
|
|
|
|
gravcreate(5, 1);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate2++;
|
|
|
|
if(game.swnstate2==3)
|
|
|
|
{
|
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 30; //return to decision state
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate--;
|
|
|
|
game.swndelay = 10; //return to decision state
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 14:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(0, 0, 0);
|
|
|
|
gravcreate(5, 1, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
game.swnstate++;
|
|
|
|
game.swndelay = 20; //return to decision state
|
|
|
|
break;
|
|
|
|
case 15:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(1, 0);
|
|
|
|
gravcreate(4, 1);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
game.swnstate++;
|
|
|
|
game.swndelay = 20; //return to decision state
|
|
|
|
break;
|
|
|
|
case 16:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(2, 0);
|
|
|
|
gravcreate(3, 1);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
game.swnstate++;
|
|
|
|
game.swndelay = 20; //return to decision state
|
|
|
|
break;
|
|
|
|
case 17:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(3, 0);
|
|
|
|
gravcreate(2, 1);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
game.swnstate++;
|
|
|
|
game.swndelay = 20; //return to decision state
|
|
|
|
break;
|
|
|
|
case 18:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(4, 0);
|
|
|
|
gravcreate(1, 1);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
game.swnstate++;
|
|
|
|
game.swndelay = 20; //return to decision state
|
|
|
|
break;
|
|
|
|
case 19:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(5, 0);
|
|
|
|
gravcreate(0, 1);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
game.swnstate=0;
|
|
|
|
game.swndelay = 20; //return to decision state
|
|
|
|
break;
|
|
|
|
case 20:
|
|
|
|
game.swnstate4++;
|
|
|
|
if(game.swnstate3==0)
|
|
|
|
{
|
|
|
|
game.swnstate2++;
|
|
|
|
if (game.swnstate2 >= 6)
|
|
|
|
{
|
|
|
|
game.swnstate3 = 1;
|
|
|
|
game.swnstate2--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate2--;
|
|
|
|
if (game.swnstate2 < 0)
|
|
|
|
{
|
|
|
|
game.swnstate3 = 0;
|
|
|
|
game.swnstate2++;
|
|
|
|
}
|
|
|
|
}
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(-150, 58 + (int(game.swnstate2) * 20), 23, 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
if(game.swnstate4<=6)
|
|
|
|
{
|
|
|
|
game.swnstate = 20;
|
|
|
|
game.swndelay = 10; //return to decision state
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 10; //return to decision state
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 21:
|
|
|
|
game.swnstate4++;
|
|
|
|
if(game.swnstate3==0)
|
|
|
|
{
|
|
|
|
game.swnstate2++;
|
|
|
|
if (game.swnstate2 >= 6)
|
|
|
|
{
|
|
|
|
game.swnstate3 = 1;
|
|
|
|
game.swnstate2--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate2--;
|
|
|
|
if (game.swnstate2 < 0)
|
|
|
|
{
|
|
|
|
game.swnstate3 = 0;
|
|
|
|
game.swnstate2++;
|
|
|
|
}
|
|
|
|
}
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(320+150, 58 + (int(game.swnstate2) * 20), 23, 1, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
if(game.swnstate4<=6)
|
|
|
|
{
|
|
|
|
game.swnstate = 21;
|
|
|
|
game.swndelay = 10; //return to decision state
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 10; //return to decision state
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 22:
|
|
|
|
game.swnstate4++;
|
|
|
|
//left and right compliments
|
|
|
|
game.swnstate2 = int(fRandom() * 6);
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(-150, 58 + (game.swnstate2 * 20), 23, 0, 0);
|
|
|
|
createentity(320 + 150, 58 + ((5 - game.swnstate2) * 20), 23, 1, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
if(game.swnstate4<=12)
|
|
|
|
{
|
|
|
|
game.swnstate = 22;
|
|
|
|
game.swndelay = 18; //return to decision state
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 18; //return to decision state
|
|
|
|
}
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
break;
|
|
|
|
case 23:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(1, 0);
|
|
|
|
gravcreate(2, 0, 15);
|
|
|
|
gravcreate(2, 0, -15);
|
|
|
|
gravcreate(3, 0, 15);
|
|
|
|
gravcreate(3, 0, -15);
|
|
|
|
gravcreate(4, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 15; //return to decision state
|
|
|
|
break;
|
|
|
|
case 24:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(1, 1);
|
|
|
|
gravcreate(2, 1, 15);
|
|
|
|
gravcreate(2, 1, -15);
|
|
|
|
gravcreate(3, 1, 15);
|
|
|
|
gravcreate(3, 1, -15);
|
|
|
|
gravcreate(4, 1);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 15; //return to decision state
|
|
|
|
break;
|
|
|
|
case 25:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(0, 0);
|
|
|
|
gravcreate(1, 1,0,10);
|
|
|
|
gravcreate(4, 1,0,-10);
|
|
|
|
gravcreate(5, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 20; //return to decision state
|
|
|
|
break;
|
|
|
|
case 26:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(0, 1, 0);
|
|
|
|
gravcreate(1, 1, 10);
|
|
|
|
gravcreate(4, 1, 40);
|
|
|
|
gravcreate(5, 1, 50);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 20; //return to decision state
|
|
|
|
break;
|
|
|
|
case 27:
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(0, 0, 0);
|
|
|
|
gravcreate(1, 0, 10);
|
|
|
|
gravcreate(4, 0, 40);
|
|
|
|
gravcreate(5, 0, 50);
|
2020-01-01 21:29:24 +01:00
|
|
|
game.swnstate = 0;
|
|
|
|
game.swndelay = 20; //return to decision state
|
|
|
|
break;
|
|
|
|
case 28:
|
|
|
|
game.swnstate4++;
|
|
|
|
game.swnstate2 = int(fRandom() * 6);
|
2020-03-31 02:46:36 +02:00
|
|
|
createentity(-150, 58 + (game.swnstate2 * 20), 23, 0, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
if(game.swnstate4<=6)
|
|
|
|
{
|
|
|
|
game.swnstate = 28;
|
|
|
|
game.swndelay = 8; //return to decision state
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate = 3;
|
|
|
|
game.swndelay = 15; //return to decision state
|
|
|
|
}
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
break;
|
|
|
|
case 29:
|
|
|
|
game.swnstate4++;
|
|
|
|
game.swnstate2 = int(fRandom() * 6);
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(game.swnstate2, 1);
|
2020-01-01 21:29:24 +01:00
|
|
|
if(game.swnstate4<=6)
|
|
|
|
{
|
|
|
|
game.swnstate = 29;
|
|
|
|
game.swndelay = 8; //return to decision state
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate = 3;
|
|
|
|
game.swndelay = 15; //return to decision state
|
|
|
|
}
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
break;
|
|
|
|
case 30:
|
|
|
|
game.swnstate4++;
|
|
|
|
game.swnstate2 = int(fRandom() * 3);
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(game.swnstate2, 0);
|
|
|
|
gravcreate(5-game.swnstate2, 0);
|
2020-01-01 21:29:24 +01:00
|
|
|
if(game.swnstate4<=2)
|
|
|
|
{
|
|
|
|
game.swnstate = 30;
|
|
|
|
game.swndelay = 14; //return to decision state
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate = 3;
|
|
|
|
game.swndelay = 15; //return to decision state
|
|
|
|
}
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
break;
|
|
|
|
case 31:
|
|
|
|
game.swnstate4++;
|
|
|
|
game.swnstate2 = int(fRandom() * 3);
|
2020-03-31 02:46:36 +02:00
|
|
|
gravcreate(game.swnstate2, 1);
|
|
|
|
gravcreate(5-game.swnstate2, 1);
|
2020-01-01 21:29:24 +01:00
|
|
|
if(game.swnstate4<=2)
|
|
|
|
{
|
|
|
|
game.swnstate = 31;
|
|
|
|
game.swndelay = 14; //return to decision state
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swnstate = 3;
|
|
|
|
game.swndelay = 15; //return to decision state
|
|
|
|
}
|
|
|
|
game.swnstate2 = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.swndelay--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::createblock( int t, int xp, int yp, int w, int h, int trig /*= 0*/ )
|
|
|
|
{
|
2020-04-04 01:11:02 +02:00
|
|
|
k = blocks.size();
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-04 01:11:02 +02:00
|
|
|
blockclass block;
|
2020-01-01 21:29:24 +01:00
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
case BLOCK: //Block
|
2020-04-04 01:11:02 +02:00
|
|
|
block.type = BLOCK;
|
|
|
|
block.xp = xp;
|
|
|
|
block.yp = yp;
|
|
|
|
block.wp = w;
|
|
|
|
block.hp = h;
|
|
|
|
block.rectset(xp, yp, w, h);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case TRIGGER: //Trigger
|
2020-04-04 01:11:02 +02:00
|
|
|
block.type = TRIGGER;
|
|
|
|
block.x = xp;
|
|
|
|
block.y = yp;
|
|
|
|
block.wp = w;
|
|
|
|
block.hp = h;
|
|
|
|
block.rectset(xp, yp, w, h);
|
|
|
|
block.trigger = trig;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case DAMAGE: //Damage
|
2020-04-04 01:11:02 +02:00
|
|
|
block.type = DAMAGE;
|
|
|
|
block.x = xp;
|
|
|
|
block.y = yp;
|
|
|
|
block.wp = w;
|
|
|
|
block.hp = h;
|
|
|
|
block.rectset(xp, yp, w, h);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case DIRECTIONAL: //Directional
|
2020-04-04 01:11:02 +02:00
|
|
|
block.type = DIRECTIONAL;
|
|
|
|
block.x = xp;
|
|
|
|
block.y = yp;
|
|
|
|
block.wp = w;
|
|
|
|
block.hp = h;
|
|
|
|
block.rectset(xp, yp, w, h);
|
|
|
|
block.trigger = trig;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case SAFE: //Safe block
|
2020-04-04 01:11:02 +02:00
|
|
|
block.type = SAFE;
|
|
|
|
block.xp = xp;
|
|
|
|
block.yp = yp;
|
|
|
|
block.wp = w;
|
|
|
|
block.hp = h;
|
|
|
|
block.rectset(xp, yp, w, h);
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case ACTIVITY: //Activity Zone
|
2020-04-04 01:11:02 +02:00
|
|
|
block.type = ACTIVITY;
|
|
|
|
block.x = xp;
|
|
|
|
block.y = yp;
|
|
|
|
block.wp = w;
|
|
|
|
block.hp = h;
|
|
|
|
block.rectset(xp, yp, w, h);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
//Ok, each and every activity zone in the game is initilised here. "Trig" in this case is a variable that
|
|
|
|
//assigns all the details.
|
|
|
|
switch(trig)
|
|
|
|
{
|
|
|
|
case 0: //testing zone
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to explode";
|
|
|
|
block.script = "intro";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=1;
|
|
|
|
break;
|
|
|
|
case 1:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to talk to Violet";
|
|
|
|
block.script = "talkpurple";
|
|
|
|
block.setblockcolour("purple");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 2:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to talk to Vitellary";
|
|
|
|
block.script = "talkyellow";
|
|
|
|
block.setblockcolour("yellow");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 3:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to talk to Vermilion";
|
|
|
|
block.script = "talkred";
|
|
|
|
block.setblockcolour("red");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 4:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to talk to Verdigris";
|
|
|
|
block.script = "talkgreen";
|
|
|
|
block.setblockcolour("green");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 5:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to talk to Victoria";
|
|
|
|
block.script = "talkblue";
|
|
|
|
block.setblockcolour("blue");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 6:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_station_1";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 7:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_outside_1";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 8:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_outside_2";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 9:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_outside_3";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 10:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_outside_4";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 11:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_outside_5";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 12:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_outside_6";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 13:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_finallevel";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 14:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_station_2";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 15:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_station_3";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 16:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_station_4";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 17:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_warp_1";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 18:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_warp_2";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 19:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_lab_1";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 20:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_lab_2";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 21:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_secretlab";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 22:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_shipcomputer";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 23:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminals";
|
|
|
|
block.script = "terminal_radio";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 24:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "terminal_jukebox";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 25:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Passion for Exploring";
|
|
|
|
block.script = "terminal_juke1";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 26:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Pushing Onwards";
|
|
|
|
block.script = "terminal_juke2";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 27:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Positive Force";
|
|
|
|
block.script = "terminal_juke3";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 28:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Presenting VVVVVV";
|
|
|
|
block.script = "terminal_juke4";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 29:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Potential for Anything";
|
|
|
|
block.script = "terminal_juke5";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 30:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Predestined Fate";
|
|
|
|
block.script = "terminal_juke6";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 31:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Pipe Dream";
|
|
|
|
block.script = "terminal_juke7";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 32:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Popular Potpourri";
|
|
|
|
block.script = "terminal_juke8";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 33:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Pressure Cooker";
|
|
|
|
block.script = "terminal_juke9";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 34:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "ecroF evitisoP";
|
|
|
|
block.script = "terminal_juke10";
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
case 35:
|
2020-04-04 01:11:02 +02:00
|
|
|
block.prompt = "Press ENTER to activate terminal";
|
|
|
|
block.script = "custom_"+customscript;
|
|
|
|
block.setblockcolour("orange");
|
2020-01-01 21:29:24 +01:00
|
|
|
trig=0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2020-04-04 01:11:02 +02:00
|
|
|
|
|
|
|
blocks.push_back(block);
|
2020-01-01 21:29:24 +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);'.
2020-06-13 21:00:04 +02:00
|
|
|
// Remove entity, and return true if entity was successfully removed
|
|
|
|
bool entityclass::removeentity(int t)
|
2020-04-03 22:03:02 +02:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t > (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("removeentity() out-of-bounds!");
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (entities[t].rule == 0 && t == getplayer())
|
|
|
|
{
|
|
|
|
// Don't remove the player entity!
|
|
|
|
return false;
|
2020-05-05 01:41:30 +02:00
|
|
|
}
|
2020-04-03 22:50:16 +02:00
|
|
|
entities.erase(entities.begin() + t);
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return true;
|
2020-04-03 22:03:02 +02:00
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
void entityclass::removeallblocks()
|
|
|
|
{
|
2020-04-04 01:11:02 +02:00
|
|
|
blocks.clear();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::removeblock( int t )
|
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t > (int) blocks.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("removeblock() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-04-04 01:11:02 +02:00
|
|
|
blocks.erase(blocks.begin() + t);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::removeblockat( int x, int y )
|
|
|
|
{
|
2020-04-04 01:11:02 +02:00
|
|
|
for (size_t i = 0; i < blocks.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 01:11:02 +02:00
|
|
|
if(blocks[i].xp == int(x) && blocks[i].yp == int(y)) removeblock_iter(i);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::removetrigger( int t )
|
|
|
|
{
|
2020-04-04 01:11:02 +02:00
|
|
|
for(size_t i=0; i<blocks.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
if(blocks[i].type == TRIGGER && blocks[i].trigger == t)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
removeblock_iter(i);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::copylinecross( int t )
|
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t > (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("copylinecross() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
//Copy entity t into the first free linecrosskludge entity
|
2020-04-03 22:50:16 +02:00
|
|
|
linecrosskludge.push_back(entities[t]);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::revertlinecross( int t, int s )
|
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t > (int) entities.size() || s < 0 || s > (int) linecrosskludge.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("revertlinecross() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
//Restore entity t info from linecrossing s
|
|
|
|
entities[t].onentity = linecrosskludge[s].onentity;
|
|
|
|
entities[t].state = linecrosskludge[s].state;
|
|
|
|
entities[t].life = linecrosskludge[s].life;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool entityclass::gridmatch( int p1, int p2, int p3, int p4, int p11, int p21, int p31, int p41 )
|
|
|
|
{
|
|
|
|
if (p1 == p11 && p2 == p21 && p3 == p31 && p4 == p41) return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int entityclass::crewcolour( int t )
|
|
|
|
{
|
|
|
|
//Return the colour of the indexed crewmate
|
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
return 0;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
return 20;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
return 14;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
return 15;
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
return 13;
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
return 16;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
void entityclass::createentity( float xp, float yp, int t, float vx /*= 0*/, float vy /*= 0*/, int p1 /*= 0*/, int p2 /*= 0*/, int p3 /*= 320*/, int p4 /*= 240 */ )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
k = entities.size();
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
//Size 0 is a sprite
|
|
|
|
//Size 1 is a tile
|
|
|
|
//Beyond that are special cases (to do)
|
|
|
|
//Size 2 is a moving platform of width 4 (32)
|
|
|
|
//Size 3 is apparently a "bug chunky pixel"
|
|
|
|
//Size 4 is a coin/small pickup
|
|
|
|
//Size 5 is a horizontal line, 6 is vertical
|
|
|
|
|
|
|
|
//Rule 0 is the playable character
|
|
|
|
//Rule 1 is anything harmful
|
|
|
|
//Rule 2 is anything decorative (no collisions)
|
|
|
|
//Rule 3 is anything that results in an entity to entity collision and state change
|
|
|
|
//Rule 4 is a horizontal line, 5 is vertical
|
|
|
|
//Rule 6 is a crew member
|
|
|
|
|
2020-06-30 00:27:23 +02:00
|
|
|
#if !defined(NO_CUSTOM_LEVELS)
|
|
|
|
// Special case for gray Warp Zone tileset!
|
|
|
|
int room = game.roomx-100 + (game.roomy-100) * ed.maxwidth;
|
|
|
|
bool custom_gray = room >= 0 && room < 400
|
|
|
|
&& ed.level[room].tileset == 3 && ed.level[room].tilecol == 6;
|
|
|
|
#else
|
|
|
|
bool custom_gray = false;
|
|
|
|
#endif
|
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
entclass entity;
|
2020-04-29 01:17:10 +02:00
|
|
|
entity.xp = xp;
|
|
|
|
entity.yp = yp;
|
|
|
|
entity.oldxp = xp;
|
|
|
|
entity.oldyp = yp;
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.type = t;
|
2020-01-01 21:29:24 +01:00
|
|
|
switch(t)
|
|
|
|
{
|
|
|
|
case 0: //Player
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 0; //Playable character
|
|
|
|
entity.tile = 0;
|
|
|
|
entity.colour = 0;
|
|
|
|
entity.cx = 6;
|
|
|
|
entity.cy = 2;
|
|
|
|
entity.w = 12;
|
|
|
|
entity.h = 21;
|
|
|
|
entity.dir = 1;
|
|
|
|
|
|
|
|
if( (vx)==1) entity.invis = true;
|
|
|
|
|
|
|
|
entity.gravity = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
2020-01-16 14:31:01 +01:00
|
|
|
case 1: //Simple enemy, bouncing off the walls
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 1;
|
|
|
|
entity.behave = vx;
|
|
|
|
entity.para = vy;
|
|
|
|
entity.w = 16;
|
|
|
|
entity.h = 16;
|
|
|
|
entity.cx = 0;
|
|
|
|
entity.cy = 0;
|
|
|
|
|
|
|
|
entity.x1 = p1;
|
|
|
|
entity.y1 = p2;
|
|
|
|
entity.x2 = p3;
|
|
|
|
entity.y2 = p4;
|
|
|
|
|
|
|
|
entity.harmful = true;
|
|
|
|
entity.tile = 24;
|
|
|
|
entity.animate = 0;
|
|
|
|
entity.colour = 8;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if (game.roomy == 111 && (game.roomx >= 113 && game.roomx <= 117))
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.setenemy(0);
|
|
|
|
entity.setenemyroom(game.roomx, game.roomy); //For colour
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else if (game.roomx == 113 && (game.roomy <= 110 && game.roomy >= 108))
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.setenemy(1);
|
|
|
|
entity.setenemyroom(game.roomx, game.roomy); //For colour
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else if (game.roomx == 113 && game.roomy == 107)
|
|
|
|
{
|
|
|
|
//MAVVERRRICK
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 96;
|
|
|
|
entity.colour = 6;
|
|
|
|
entity.size = 9;
|
|
|
|
entity.w = 64;
|
|
|
|
entity.h = 44;
|
|
|
|
entity.animate = 4;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.setenemyroom(game.roomx, game.roomy);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2: //A moving platform
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 2;
|
|
|
|
entity.type = 1;
|
|
|
|
entity.size = 2;
|
|
|
|
entity.tile = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if (customplatformtile > 0){
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = customplatformtile;
|
2020-01-01 21:29:24 +01:00
|
|
|
}else if (platformtile > 0) {
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = platformtile;
|
2020-01-01 21:29:24 +01:00
|
|
|
}else{
|
|
|
|
//appearance again depends on location
|
2020-04-03 22:50:16 +02:00
|
|
|
if (gridmatch(p1, p2, p3, p4, 100, 70, 320, 160)) entity.tile = 616;
|
|
|
|
if (gridmatch(p1, p2, p3, p4, 72, 0, 248, 240)) entity.tile = 610;
|
|
|
|
if (gridmatch(p1, p2, p3, p4, -20, 0, 320, 240)) entity.tile = 413;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
if (gridmatch(p1, p2, p3, p4, -96, -72, 400, 312)) entity.tile = 26;
|
|
|
|
if (gridmatch(p1, p2, p3, p4, -32, -40, 352, 264)) entity.tile = 27;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.w = 32;
|
|
|
|
entity.h = 8;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-02 22:42:50 +02:00
|
|
|
if (int(vx) <= 1) vertplatforms = true;
|
|
|
|
if (int(vx) >= 2 && int(vx) <= 5) horplatforms = true;
|
|
|
|
if (int(vx) == 14 || int(vx) == 15) horplatforms = true; //special case for last part of Space Station
|
|
|
|
if (int(vx) >= 6 && int(vx) <= 7) vertplatforms = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if (int(vx) >= 10 && int(vx) <= 11)
|
|
|
|
{
|
|
|
|
//Double sized threadmills
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.w = 64;
|
|
|
|
entity.h = 8;
|
2020-01-01 21:29:24 +01:00
|
|
|
vx -= 2;
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.size = 8;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.behave = vx;
|
|
|
|
entity.para = vy;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if (int(vx) >= 8 && int(vx) <= 9)
|
|
|
|
{
|
|
|
|
horplatforms = true; //threadmill!
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.animate = 10;
|
2020-01-01 21:29:24 +01:00
|
|
|
if(customplatformtile>0){
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = customplatformtile+4;
|
|
|
|
if (int(vx) == 8) entity.tile += 4;
|
|
|
|
if (int(vx) == 9) entity.animate = 11;
|
2020-01-01 21:29:24 +01:00
|
|
|
}else{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.settreadmillcolour(game.roomx, game.roomy);
|
|
|
|
if (int(vx) == 8) entity.tile += 40;
|
|
|
|
if (int(vx) == 9) entity.animate = 11;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.animate = 100;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.x1 = p1;
|
|
|
|
entity.y1 = p2;
|
|
|
|
entity.x2 = p3;
|
|
|
|
entity.y2 = p4;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.isplatform = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
createblock(0, xp, yp, 32, 8);
|
|
|
|
break;
|
|
|
|
case 3: //Disappearing platforms
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 2;
|
|
|
|
entity.size = 2;
|
|
|
|
entity.tile = 2;
|
2020-01-01 21:29:24 +01:00
|
|
|
//appearance again depends on location
|
|
|
|
if(customplatformtile>0)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile=customplatformtile;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else if (vx > 0)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = int(vx);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
if(game.roomx==49 && game.roomy==52) entity.tile = 18;
|
|
|
|
if (game.roomx == 50 && game.roomy == 52) entity.tile = 22;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.cy = -1;
|
|
|
|
entity.w = 32;
|
|
|
|
entity.h = 10;
|
|
|
|
entity.behave = vx;
|
|
|
|
entity.para = vy;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.animate = 100;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
createblock(0, xp, yp, 32, 8);
|
|
|
|
break;
|
|
|
|
case 4: //Breakable blocks
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 6;
|
|
|
|
entity.type = 3;
|
|
|
|
entity.size = 1;
|
|
|
|
entity.tile = 10;
|
|
|
|
entity.cy = -1;
|
|
|
|
entity.w = 8;
|
|
|
|
entity.h = 10;
|
|
|
|
entity.behave = vx;
|
|
|
|
entity.para = vy;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.animate = 100;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
createblock(0, xp, yp, 8, 8);
|
|
|
|
break;
|
|
|
|
case 5: //Gravity Tokens
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 4;
|
|
|
|
entity.size = 0;
|
|
|
|
entity.tile = 11;
|
|
|
|
entity.w = 16;
|
|
|
|
entity.h = 16;
|
|
|
|
entity.behave = vx;
|
|
|
|
entity.para = vy;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.animate = 100;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 6: //Decorative particles
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 2;
|
|
|
|
entity.type = 5; //Particles
|
|
|
|
entity.colour = 1;
|
|
|
|
entity.size = 3;
|
|
|
|
entity.vx = vx;
|
|
|
|
entity.vy = vy;
|
|
|
|
|
|
|
|
entity.life = 12;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 7: //Decorative particles
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 2;
|
|
|
|
entity.type = 5; //Particles
|
|
|
|
entity.colour = 2;
|
|
|
|
entity.size = 3;
|
|
|
|
entity.vx = vx;
|
|
|
|
entity.vy = vy;
|
|
|
|
|
|
|
|
entity.life = 12;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 8: //Small collectibles
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 6;
|
|
|
|
entity.size = 4;
|
|
|
|
entity.tile = 48;
|
|
|
|
entity.w = 8;
|
|
|
|
entity.h = 8;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.animate = 100;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
//Check if it's already been collected
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.para = vx;
|
Prevent out-of-bounds indexing with trinket/crewmate IDs
If a trinket or crewmate ID is out-of-bounds, it will not be created.
This is not only because the `collect`/`customcollect` check in
entityclass::createentity() would then be out-of-bounds, but also
touching it would also be out-of-bounds, too.
Display trinkets will always be created if the ID is out-of-bounds.
Apparently some people (@AllyTally) have been creating display trinkets
with IDs of -1 in order to get a display trinket that always shows up,
which is rather horrifying. But it makes sense, there's a lot more
nonzero int values than there are the amount of int values that are
zero, so it's fairly likely that the `collect` check will always come up
to be true (nonzero). Also, it's more useful to be able to have a
display trinket that always shows up without having to collect a trinket
beforehand, than it is to have it not be created (because technically by
default, you're already in the world where you don't have it created).
Display trinkets still have their `para` set to their ID, though, and if
they managed to gain an `onentity` of 1, bad things could happen... So
just to be sure, I added INBOUNDS checks to crewmates and trinkets in
entityclass::updateentities() so no UB will happen if you collect a
crewmate/trinket with an out-of-bounds ID. Also, I de-duplicated the
`collect`/`customcollect` setting, too.
2020-06-15 23:20:37 +02:00
|
|
|
if (!INBOUNDS(vx, collect) || collect[vx]) return;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 9: //Something Shiny
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 7;
|
|
|
|
entity.size = 0;
|
|
|
|
entity.tile = 22;
|
|
|
|
entity.w = 16;
|
|
|
|
entity.h = 16;
|
|
|
|
entity.colour = 3;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.animate = 100;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
//Check if it's already been collected
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.para = vx;
|
2020-04-09 08:56:36 +02:00
|
|
|
if (collect[vx]) return;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 10: //Savepoint
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 8;
|
|
|
|
entity.size = 0;
|
|
|
|
entity.tile = 20 + vx;
|
|
|
|
entity.w = 16;
|
|
|
|
entity.h = 16;
|
|
|
|
entity.colour = 4;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.animate = 100;
|
|
|
|
entity.para = vy;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if (game.savepoint == (vy))
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.colour = 5;
|
|
|
|
entity.onentity = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (game.nodeathmode)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
return;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 11: //Horizontal Gravity Line
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 4;
|
|
|
|
entity.type = 9;
|
|
|
|
entity.size = 5;
|
|
|
|
entity.life = 0;
|
|
|
|
entity.w = vx;
|
|
|
|
entity.h = 1;
|
|
|
|
entity.onentity = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 12: //Vertical Gravity Line
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 5;
|
|
|
|
entity.type = 10;
|
|
|
|
entity.size = 6;
|
|
|
|
entity.life = 0;
|
|
|
|
entity.w = 1;
|
|
|
|
entity.h = vx;
|
|
|
|
//entity.colour = 0;
|
|
|
|
entity.onentity = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 13: //Warp token
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 11;
|
|
|
|
entity.size = 0;
|
|
|
|
entity.tile = 18;
|
|
|
|
entity.w = 16;
|
|
|
|
entity.h = 16;
|
|
|
|
entity.colour = 10;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.animate = 2;
|
2020-01-01 21:29:24 +01:00
|
|
|
//Added in port, hope it doesn't break anything
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.behave = vx;
|
|
|
|
entity.para = vy;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 14: // Teleporter
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 100;
|
|
|
|
entity.size = 7;
|
|
|
|
entity.tile = 1; //inactive
|
|
|
|
entity.w = 96;
|
|
|
|
entity.h = 96;
|
|
|
|
entity.colour = 100;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.animate = 100;
|
|
|
|
entity.para = vy;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 15: // Crew Member (warp zone)
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 6;
|
|
|
|
entity.type = 12; //A special case!
|
|
|
|
entity.tile = 144;
|
|
|
|
entity.colour = 13; //144 for sad :(
|
|
|
|
entity.cx = 6;
|
|
|
|
entity.cy = 2;
|
|
|
|
entity.w = 12;
|
|
|
|
entity.h = 21;
|
|
|
|
entity.dir = 0;
|
|
|
|
|
|
|
|
entity.state = vx;
|
|
|
|
|
|
|
|
entity.gravity = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 16: // Crew Member, upside down (space station)
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 7;
|
|
|
|
entity.type = 12; //A special case!
|
|
|
|
entity.tile = 144+6;
|
|
|
|
entity.colour = 14; //144 for sad (upside down+12):(
|
|
|
|
entity.cx = 6;
|
|
|
|
entity.cy = 2;
|
|
|
|
entity.w = 12;
|
|
|
|
entity.h = 21;
|
|
|
|
entity.dir = 1;
|
|
|
|
|
|
|
|
entity.state = vx;
|
|
|
|
|
|
|
|
entity.gravity = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 17: // Crew Member (Lab)
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 6;
|
|
|
|
entity.type = 12; //A special case!
|
|
|
|
entity.tile = 144;
|
|
|
|
entity.colour = 16; //144 for sad :(
|
|
|
|
entity.cx = 6;
|
|
|
|
entity.cy = 2;
|
|
|
|
entity.w = 12;
|
|
|
|
entity.h = 21;
|
|
|
|
entity.dir = 1;
|
|
|
|
|
|
|
|
entity.state = vx;
|
|
|
|
|
|
|
|
entity.gravity = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 18: // Crew Member (Ship)
|
|
|
|
//This is the scriping crewmember
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 6;
|
|
|
|
entity.type = 12; //A special case!
|
|
|
|
entity.colour = vx;
|
2020-01-01 21:29:24 +01:00
|
|
|
if (int(vy) == 0)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 144;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.cx = 6;
|
|
|
|
entity.cy = 2;
|
|
|
|
entity.w = 12;
|
|
|
|
entity.h = 21;
|
|
|
|
entity.dir = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.state = p1;
|
|
|
|
entity.para = p2;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if (p1 == 17)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.dir = p2;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.gravity = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 19: // Crew Member (Ship) More tests!
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 6;
|
|
|
|
entity.type = 12; //A special case!
|
|
|
|
entity.tile = 0;
|
|
|
|
entity.colour = 6; //54 for sad :(
|
|
|
|
entity.cx = 6;
|
|
|
|
entity.cy = 2;
|
|
|
|
entity.w = 12;
|
|
|
|
entity.h = 21;
|
|
|
|
entity.dir = 1;
|
|
|
|
|
|
|
|
entity.state = vx;
|
|
|
|
|
|
|
|
entity.gravity = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 20: //Terminal
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 13;
|
|
|
|
entity.size = 0;
|
|
|
|
entity.tile = 16 + vx;
|
|
|
|
entity.w = 16;
|
|
|
|
entity.h = 16;
|
|
|
|
entity.colour = 4;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.animate = 100;
|
|
|
|
entity.para = vy;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 21: //as above, except doesn't highlight
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 13;
|
|
|
|
entity.size = 0;
|
|
|
|
entity.tile = 16 + vx;
|
|
|
|
entity.w = 16;
|
|
|
|
entity.h = 16;
|
|
|
|
entity.colour = 4;
|
|
|
|
entity.onentity = 0;
|
|
|
|
entity.animate = 100;
|
|
|
|
entity.para = vy;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 22: //Fake trinkets, only appear if you've collected them
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 7;
|
|
|
|
entity.size = 0;
|
|
|
|
entity.tile = 22;
|
|
|
|
entity.w = 16;
|
|
|
|
entity.h = 16;
|
|
|
|
entity.colour = 3;
|
|
|
|
entity.onentity = 0;
|
|
|
|
entity.animate = 100;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
//Check if it's already been collected
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.para = vx;
|
Prevent out-of-bounds indexing with trinket/crewmate IDs
If a trinket or crewmate ID is out-of-bounds, it will not be created.
This is not only because the `collect`/`customcollect` check in
entityclass::createentity() would then be out-of-bounds, but also
touching it would also be out-of-bounds, too.
Display trinkets will always be created if the ID is out-of-bounds.
Apparently some people (@AllyTally) have been creating display trinkets
with IDs of -1 in order to get a display trinket that always shows up,
which is rather horrifying. But it makes sense, there's a lot more
nonzero int values than there are the amount of int values that are
zero, so it's fairly likely that the `collect` check will always come up
to be true (nonzero). Also, it's more useful to be able to have a
display trinket that always shows up without having to collect a trinket
beforehand, than it is to have it not be created (because technically by
default, you're already in the world where you don't have it created).
Display trinkets still have their `para` set to their ID, though, and if
they managed to gain an `onentity` of 1, bad things could happen... So
just to be sure, I added INBOUNDS checks to crewmates and trinkets in
entityclass::updateentities() so no UB will happen if you collect a
crewmate/trinket with an out-of-bounds ID. Also, I de-duplicated the
`collect`/`customcollect` setting, too.
2020-06-15 23:20:37 +02:00
|
|
|
if (INBOUNDS(vx, collect) && !collect[ (vx)]) return;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 23: //SWN Enemies
|
|
|
|
//Given a different behavior, these enemies are especially for SWN mode and disappear outside the screen.
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 1;
|
|
|
|
entity.type = 23;
|
|
|
|
entity.behave = vx;
|
|
|
|
entity.para = vy;
|
|
|
|
entity.w = 16;
|
|
|
|
entity.h = 16;
|
|
|
|
entity.cx = 0;
|
|
|
|
entity.cy = 0;
|
|
|
|
|
|
|
|
entity.x1 = -2000;
|
|
|
|
entity.y1 = -100;
|
|
|
|
entity.x2 = 5200;
|
|
|
|
entity.y2 = 340;
|
|
|
|
|
|
|
|
entity.harmful = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
//initilise tiles here based on behavior
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.size = 12; //don't wrap around
|
|
|
|
entity.colour = 21;
|
|
|
|
entity.tile = 78; //default case
|
|
|
|
entity.animate = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
if (game.swngame == 1)
|
|
|
|
{
|
|
|
|
//set colour based on current state
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.colour = swncolour(game.swncolstate);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 24: // Super Crew Member
|
|
|
|
//This special crewmember is way more advanced than the usual kind, and can interact with game objects
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 6;
|
|
|
|
entity.type = 14; //A special case!
|
|
|
|
entity.colour = vx;
|
2020-01-01 21:29:24 +01:00
|
|
|
if( (vx)==16)
|
|
|
|
{
|
|
|
|
//victoria is sad!
|
|
|
|
if (int(vy) == 2) vy = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (int(vy) == 2) vy = 0;
|
|
|
|
}
|
|
|
|
if (int(vy) == 0)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 144;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.cx = 6;
|
|
|
|
entity.cy = 2;
|
|
|
|
entity.w = 12;
|
|
|
|
entity.h = 21;
|
|
|
|
entity.dir = 1;
|
|
|
|
|
|
|
|
entity.x1 = -2000;
|
|
|
|
entity.y1 = -100;
|
|
|
|
entity.x2 = 5200;
|
|
|
|
entity.y2 = 340;
|
|
|
|
|
|
|
|
entity.state = p1;
|
|
|
|
entity.para = p2;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
if (p1 == 17)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.dir = p2;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.gravity = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 25: //Trophies
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 15;
|
|
|
|
entity.size = 0;
|
|
|
|
entity.w = 16;
|
|
|
|
entity.h = 16;
|
|
|
|
entity.colour = 4;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.animate = 100;
|
|
|
|
entity.para = vy;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
//Decide tile here based on given achievement: both whether you have them and what they are
|
|
|
|
//default is just a trophy base:
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 180 + vx;
|
2020-01-01 21:29:24 +01:00
|
|
|
switch(int(vy))
|
|
|
|
{
|
|
|
|
case 1:
|
|
|
|
if(game.bestrank[0]>=3)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 184 + vx;
|
|
|
|
entity.colour = 31;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
if(game.bestrank[1]>=3)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 186 + vx;
|
|
|
|
entity.colour = 35;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
if(game.bestrank[2]>=3)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 184 + vx;
|
|
|
|
entity.colour = 33;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
if(game.bestrank[3]>=3)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 184 + vx;
|
|
|
|
entity.colour = 32;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
if(game.bestrank[4]>=3)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 184 + vx;
|
|
|
|
entity.colour = 34;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 6:
|
|
|
|
if(game.bestrank[5]>=3)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 184 + vx;
|
|
|
|
entity.colour = 30;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 7:
|
|
|
|
if(game.unlock[5])
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 188 + vx;
|
|
|
|
entity.colour = 37;
|
|
|
|
entity.h += 3;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 8:
|
|
|
|
if(game.unlock[19])
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 188 + vx;
|
|
|
|
entity.colour = 37;
|
|
|
|
entity.h += 3;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 9:
|
|
|
|
if (game.bestgamedeaths > -1)
|
|
|
|
{
|
|
|
|
if (game.bestgamedeaths <= 50)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 182 + vx;
|
|
|
|
entity.colour = 40;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
if (game.bestgamedeaths > -1)
|
|
|
|
{
|
|
|
|
if (game.bestgamedeaths <= 100)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 182 + vx;
|
|
|
|
entity.colour = 36;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
if (game.bestgamedeaths > -1)
|
|
|
|
{
|
|
|
|
if (game.bestgamedeaths <= 250)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 182 + vx;
|
|
|
|
entity.colour = 38;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
if (game.bestgamedeaths > -1)
|
|
|
|
{
|
|
|
|
if (game.bestgamedeaths <= 500)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 182 + vx;
|
|
|
|
entity.colour = 39;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 13:
|
|
|
|
if(game.swnbestrank>=1)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 182 + vx;
|
|
|
|
entity.colour = 39;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 14:
|
|
|
|
if(game.swnbestrank>=2)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = (182 + vx);
|
|
|
|
entity.colour = 39;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 15:
|
|
|
|
if(game.swnbestrank>=3)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = (182 + vx);
|
|
|
|
entity.colour = 39;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 16:
|
|
|
|
if(game.swnbestrank>=4)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = (182 + vx);
|
|
|
|
entity.colour = 38;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 17:
|
|
|
|
if(game.swnbestrank>=5)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = (182 + vx);
|
|
|
|
entity.colour = 36;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 18:
|
|
|
|
if(game.swnbestrank>=6)
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = (182 + vx);
|
|
|
|
entity.colour = 40;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 19:
|
|
|
|
if(game.unlock[20])
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 3;
|
|
|
|
entity.colour = 102;
|
|
|
|
entity.size = 13;
|
|
|
|
entity.xp -= 64;
|
|
|
|
entity.yp -= 128;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case 26: //Epilogue super warp token
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 11;
|
|
|
|
entity.size = 0;
|
|
|
|
entity.tile = 18;
|
|
|
|
entity.w = 16;
|
|
|
|
entity.h = 16;
|
|
|
|
entity.colour = 3;
|
|
|
|
entity.onentity = 0;
|
|
|
|
entity.animate = 100;
|
|
|
|
entity.para = vy;
|
|
|
|
entity.size = 13;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
|
|
|
|
case 51: //Vertical Warp Line
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 5;
|
|
|
|
entity.type = 51;
|
|
|
|
entity.size = 6;
|
|
|
|
entity.life = 0;
|
|
|
|
entity.w = 1;
|
|
|
|
entity.h = vx;
|
|
|
|
//entity.colour = 0;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.invis=true;
|
2020-01-31 04:41:53 +01:00
|
|
|
if (map.custommode) customwarpmode = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 52: //Vertical Warp Line
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 5;
|
|
|
|
entity.type = 52;
|
|
|
|
entity.size = 6;
|
|
|
|
entity.life = 0;
|
|
|
|
entity.w = 1;
|
|
|
|
entity.h = vx;
|
|
|
|
//entity.colour = 0;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.invis=true;
|
2020-01-31 04:41:53 +01:00
|
|
|
if (map.custommode) customwarpmode = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 53: //Horizontal Warp Line
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 7;
|
|
|
|
entity.type = 53;
|
|
|
|
entity.size = 5;
|
|
|
|
entity.life = 0;
|
|
|
|
entity.w = vx;
|
|
|
|
entity.h = 1;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.invis=true;
|
2020-01-31 04:41:53 +01:00
|
|
|
if (map.custommode) customwarpmode = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 54: //Horizontal Warp Line
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 7;
|
|
|
|
entity.type = 54;
|
|
|
|
entity.size = 5;
|
|
|
|
entity.life = 0;
|
|
|
|
entity.w = vx;
|
|
|
|
entity.h = 1;
|
|
|
|
entity.onentity = 1;
|
|
|
|
entity.invis=true;
|
2020-01-31 04:41:53 +01:00
|
|
|
if (map.custommode) customwarpmode = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 55: // Crew Member (custom, collectable)
|
|
|
|
//1 - position in array
|
|
|
|
//2 - colour
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 3;
|
|
|
|
entity.type = 55;
|
2020-01-01 21:29:24 +01:00
|
|
|
if(customcrewmoods[int(vy)]==1){
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 144;
|
2020-01-01 21:29:24 +01:00
|
|
|
}else{
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.tile = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.colour = crewcolour(int(vy));
|
|
|
|
entity.cx = 6;
|
|
|
|
entity.cy = 2;
|
|
|
|
entity.w = 12;
|
|
|
|
entity.h = 21;
|
|
|
|
entity.dir = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.state = 0;
|
|
|
|
entity.onentity = 1;
|
|
|
|
//entity.state = vx;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.gravity = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
//Check if it's already been collected
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.para = vx;
|
Prevent out-of-bounds indexing with trinket/crewmate IDs
If a trinket or crewmate ID is out-of-bounds, it will not be created.
This is not only because the `collect`/`customcollect` check in
entityclass::createentity() would then be out-of-bounds, but also
touching it would also be out-of-bounds, too.
Display trinkets will always be created if the ID is out-of-bounds.
Apparently some people (@AllyTally) have been creating display trinkets
with IDs of -1 in order to get a display trinket that always shows up,
which is rather horrifying. But it makes sense, there's a lot more
nonzero int values than there are the amount of int values that are
zero, so it's fairly likely that the `collect` check will always come up
to be true (nonzero). Also, it's more useful to be able to have a
display trinket that always shows up without having to collect a trinket
beforehand, than it is to have it not be created (because technically by
default, you're already in the world where you don't have it created).
Display trinkets still have their `para` set to their ID, though, and if
they managed to gain an `onentity` of 1, bad things could happen... So
just to be sure, I added INBOUNDS checks to crewmates and trinkets in
entityclass::updateentities() so no UB will happen if you collect a
crewmate/trinket with an out-of-bounds ID. Also, I de-duplicated the
`collect`/`customcollect` setting, too.
2020-06-15 23:20:37 +02:00
|
|
|
if (!INBOUNDS(vx, customcollect) || customcollect[vx]) return;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
case 56: //Custom enemy
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.rule = 1;
|
|
|
|
entity.type = 1;
|
|
|
|
entity.behave = vx;
|
|
|
|
entity.para = vy;
|
|
|
|
entity.w = 16;
|
|
|
|
entity.h = 16;
|
|
|
|
entity.cx = 0;
|
|
|
|
entity.cy = 0;
|
|
|
|
|
|
|
|
entity.x1 = p1;
|
|
|
|
entity.y1 = p2;
|
|
|
|
entity.x2 = p3;
|
|
|
|
entity.y2 = p4;
|
|
|
|
|
|
|
|
entity.harmful = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
switch(customenemy){
|
2020-04-03 22:50:16 +02:00
|
|
|
case 0: entity.setenemyroom(4+100, 0+100); break;
|
|
|
|
case 1: entity.setenemyroom(2+100, 0+100); break;
|
|
|
|
case 2: entity.setenemyroom(12+100, 3+100); break;
|
|
|
|
case 3: entity.setenemyroom(13+100, 12+100); break;
|
|
|
|
case 4: entity.setenemyroom(16+100, 9+100); break;
|
|
|
|
case 5: entity.setenemyroom(19+100, 1+100); break;
|
|
|
|
case 6: entity.setenemyroom(19+100, 2+100); break;
|
|
|
|
case 7: entity.setenemyroom(18+100, 3+100); break;
|
|
|
|
case 8: entity.setenemyroom(16+100, 0+100); break;
|
|
|
|
case 9: entity.setenemyroom(14+100, 2+100); break;
|
|
|
|
default: entity.setenemyroom(4+100, 0+100); break;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//Set colour based on room tile
|
|
|
|
//Set custom colours
|
|
|
|
if(customplatformtile>0){
|
|
|
|
int entcol=(customplatformtile/12);
|
|
|
|
switch(entcol){
|
|
|
|
//RED
|
|
|
|
case 3: case 7: case 12: case 23: case 28:
|
|
|
|
case 34: case 42: case 48: case 58:
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.colour = 6; break;
|
2020-01-01 21:29:24 +01:00
|
|
|
//GREEN
|
|
|
|
case 5: case 9: case 22: case 25: case 29:
|
|
|
|
case 31: case 38: case 46: case 52: case 53:
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.colour = 7; break;
|
2020-01-01 21:29:24 +01:00
|
|
|
//BLUE
|
|
|
|
case 1: case 6: case 14: case 27: case 33:
|
|
|
|
case 44: case 50: case 57:
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.colour = 12; break;
|
2020-01-01 21:29:24 +01:00
|
|
|
//YELLOW
|
|
|
|
case 4: case 17: case 24: case 30: case 37:
|
|
|
|
case 45: case 51: case 55:
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.colour = 9; break;
|
2020-01-01 21:29:24 +01:00
|
|
|
//PURPLE
|
|
|
|
case 2: case 11: case 15: case 19: case 32:
|
|
|
|
case 36: case 49:
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.colour = 20; break;
|
2020-01-01 21:29:24 +01:00
|
|
|
//CYAN
|
|
|
|
case 8: case 10: case 13: case 18: case 26:
|
|
|
|
case 35: case 41: case 47: case 54:
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.colour = 11; break;
|
2020-01-01 21:29:24 +01:00
|
|
|
//PINK
|
|
|
|
case 16: case 20: case 39: case 43: case 56:
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.colour = 8; break;
|
2020-01-01 21:29:24 +01:00
|
|
|
//ORANGE
|
|
|
|
case 21: case 40:
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.colour = 17; break;
|
2020-01-01 21:29:24 +01:00
|
|
|
default:
|
2020-04-03 22:50:16 +02:00
|
|
|
entity.colour = 6;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-30 00:27:23 +02:00
|
|
|
if(custom_gray){
|
|
|
|
entity.colour = 18;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
|
|
|
}
|
2020-04-03 22:50:16 +02:00
|
|
|
|
2020-04-29 01:37:55 +02:00
|
|
|
entity.drawframe = entity.tile;
|
Fix, for in-GAMEMODE sprites, their colors updating too fast
Okay, so the problem here is that Graphics::setcol() is called right
before a sprite is drawn in a render function, but render functions are
done in deltatime, meaning that the color of a sprite keeps being
recalculated every time. This only affects sprites that use fRandom()
(the other thing that can dynamically determine a color is help.glow,
but that's only updated in the fixed-timestep loop), but is especially
noticeable for sprites that flash wildly, like the teleporter, trinket,
and elephant.
To fix this, we need to make the color be recalculated only in the
fixed-timestep loop. However, this means that we MUST store the color of
the sprite SOMEWHERE for the delta-timesteps to render it, otherwise the
color calculation will just be lost or something.
So each entity now has a new attribute, `realcol`, which is the actual
raw color used to render the sprite in render functions. This is not to
be confused with their `colour` attribute, which is more akin to a color
"ID" of sorts, but which isn't an actual color.
At the end of gamelogic(), as well as when an entity is first created,
the `colour` is given to Graphics::setcol() and then `realcol` gets set
to the actual color. Then when it comes time to render the entity,
`realcol` gets used instead.
Gravitron squares are a somewhat tricky case where there's technically
TWO colors for it - one is the actual sprite itself and the other is the
indicator. However, usually the indicator and the square aren't both
onscreen at the same time, so we can simply switch the realcol between
the two as needed.
However, we can't use this system for the sprite colors used on the
title and map screen, so we'll have to do something else for those.
2020-05-01 02:34:37 +02:00
|
|
|
if (!entity.invis)
|
|
|
|
{
|
|
|
|
entity.updatecolour();
|
|
|
|
}
|
2020-05-04 20:13:41 +02:00
|
|
|
if (entity.type == 1)
|
|
|
|
{
|
|
|
|
switch (entity.animate)
|
|
|
|
{
|
|
|
|
case 0: // Simple Loop
|
|
|
|
case 1: // Simple Loop
|
|
|
|
case 2: // Simpler Loop (just two frames)
|
|
|
|
case 5: // Simpler Loop (just two frames) (slower)
|
|
|
|
case 7: // Simpler Loop (just two frames) (slower) (with directions!)
|
|
|
|
case 11: // Conveyor right
|
|
|
|
entity.drawframe++;
|
|
|
|
break;
|
2020-07-01 23:45:50 +02:00
|
|
|
case 3: // Simpler Loop (just two frames, but double sized)
|
|
|
|
case 4: // Simpler Loop (just two frames, but double sized) (as above, but slower)
|
|
|
|
case 6: // Normal Loop (four frames, double sized)
|
|
|
|
entity.drawframe += 2;
|
|
|
|
break;
|
2020-05-04 20:13:41 +02:00
|
|
|
case 10: // Conveyor left
|
|
|
|
entity.drawframe += 3;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entity.type == 2 && entity.animate == 2)
|
|
|
|
{
|
|
|
|
entity.drawframe++;
|
|
|
|
}
|
2020-04-29 01:37:55 +02:00
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
entities.push_back(entity);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
//Returns true if entity is removed
|
|
|
|
bool entityclass::updateentities( int i )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (i < 0 || i >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("updateentities() out-of-bounds!");
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
return true;
|
2020-05-05 01:41:30 +02:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
if(entities[i].statedelay<=0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
switch(entities[i].type)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
case 0: //Player
|
|
|
|
break;
|
|
|
|
case 1: //Movement behaviors
|
|
|
|
//Enemies can have a number of different behaviors:
|
|
|
|
switch(entities[i].behave)
|
|
|
|
{
|
|
|
|
case 0: //Bounce, Start moving down
|
|
|
|
if (entities[i].state == 0) //Init
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].state = 3;
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
bool entitygone = updateentities(i);
|
|
|
|
if (entitygone) return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (entities[i].state == 1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[i].outside()) entities[i].state = entities[i].onwall;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 2)
|
|
|
|
{
|
|
|
|
entities[i].vy = -entities[i].para;
|
|
|
|
entities[i].onwall = 3;
|
|
|
|
entities[i].state = 1;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 3)
|
|
|
|
{
|
|
|
|
entities[i].vy = entities[i].para;
|
|
|
|
entities[i].onwall = 2;
|
|
|
|
entities[i].state = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
case 1: //Bounce, Start moving up
|
|
|
|
if (entities[i].state == 0) //Init
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
entities[i].state = 2;
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
bool entitygone = updateentities(i);
|
|
|
|
if (entitygone) return true;
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
else if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
if (entities[i].outside()) entities[i].state = entities[i].onwall;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else if (entities[i].state == 2)
|
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].vy = -entities[i].para;
|
|
|
|
entities[i].onwall = 3;
|
|
|
|
entities[i].state = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else if (entities[i].state == 3)
|
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].vy = entities[i].para;
|
|
|
|
entities[i].onwall = 2;
|
|
|
|
entities[i].state = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
break;
|
|
|
|
case 2: //Bounce, Start moving left
|
|
|
|
if (entities[i].state == 0) //Init
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].state = 3;
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
bool entitygone = updateentities(i);
|
|
|
|
if (entitygone) return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (entities[i].state == 1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[i].outside()) entities[i].state = entities[i].onwall;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 2)
|
|
|
|
{
|
|
|
|
entities[i].vx = entities[i].para;
|
|
|
|
entities[i].onwall = 3;
|
|
|
|
entities[i].state = 1;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 3)
|
|
|
|
{
|
|
|
|
entities[i].vx = -entities[i].para;
|
|
|
|
entities[i].onwall = 2;
|
|
|
|
entities[i].state = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
case 3: //Bounce, Start moving right
|
|
|
|
if (entities[i].state == 0) //Init
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].state = 3;
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
bool entitygone = updateentities(i);
|
|
|
|
if (entitygone) return true;
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
else if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
if (entities[i].outside()) entities[i].state = entities[i].onwall;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else if (entities[i].state == 2)
|
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].vx = -entities[i].para;
|
|
|
|
entities[i].onwall = 3;
|
|
|
|
entities[i].state = 1;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 3)
|
|
|
|
{
|
|
|
|
entities[i].vx = entities[i].para;
|
|
|
|
entities[i].onwall = 2;
|
|
|
|
entities[i].state = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
case 4: //Always move left
|
|
|
|
if (entities[i].state == 0) //Init
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].vx = entities[i].para;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
case 5: //Always move right
|
2020-01-01 21:29:24 +01:00
|
|
|
if (entities[i].state == 0)
|
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//Init
|
|
|
|
entities[i].vx = static_cast<int>(entities[i].para);
|
|
|
|
entities[i].state = 1;
|
|
|
|
entities[i].onwall = 2;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 2)
|
|
|
|
{
|
|
|
|
entities[i].vx = 0;
|
|
|
|
entities[i].onwall = 0;
|
|
|
|
entities[i].xp -= static_cast<int>(entities[i].para);
|
|
|
|
entities[i].statedelay=8;
|
|
|
|
entities[i].state=0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
case 6: //Always move up
|
|
|
|
if (entities[i].state == 0) //Init
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].vy = static_cast<int>(entities[i].para);
|
|
|
|
entities[i].state = 1;
|
|
|
|
entities[i].onwall = 2;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 2)
|
|
|
|
{
|
|
|
|
entities[i].vy = static_cast<int>(-entities[i].para);
|
|
|
|
entities[i].onwall = 0;
|
|
|
|
entities[i].yp -= (entities[i].para);
|
|
|
|
entities[i].statedelay=8;
|
|
|
|
entities[i].state=0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
case 7: //Always move down
|
|
|
|
if (entities[i].state == 0) //Init
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].vx = static_cast<int>(entities[i].para);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
case 8:
|
|
|
|
case 9:
|
|
|
|
//Threadmill: don't move, just impart velocity
|
|
|
|
if (entities[i].state == 0) //Init
|
|
|
|
{
|
|
|
|
entities[i].vx = 0;
|
|
|
|
entities[i].state = 1;
|
|
|
|
entities[i].onwall = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
//Emitter: shoot an enemy every so often
|
|
|
|
if (entities[i].state == 0)
|
|
|
|
{
|
|
|
|
createentity(entities[i].xp+28, entities[i].yp, 1, 10, 1);
|
|
|
|
entities[i].state = 1;
|
|
|
|
entities[i].statedelay = 12;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
entities[i].state = 0;
|
|
|
|
}
|
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
case 11: //Always move right, destroy when outside screen
|
|
|
|
if (entities[i].state == 0) //Init
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].vx = entities[i].para;
|
|
|
|
entities[i].state = 1;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 1)
|
|
|
|
{
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
if (entities[i].xp >= 335)
|
|
|
|
{
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
if (game.roomx == 117)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
if (entities[i].xp >= (33*8)-32)
|
|
|
|
{
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
//collector for LIES
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
case 12:
|
|
|
|
//Emitter: shoot an enemy every so often (up)
|
|
|
|
if (entities[i].state == 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
createentity(entities[i].xp, entities[i].yp, 1, 12, 1);
|
|
|
|
entities[i].state = 1;
|
|
|
|
entities[i].statedelay = 16;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
entities[i].state = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 13: //Always move up, destroy when outside screen
|
|
|
|
if (entities[i].state == 0) //Init
|
|
|
|
{
|
|
|
|
entities[i].vy = entities[i].para;
|
|
|
|
entities[i].state = 1;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 1)
|
|
|
|
{
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
if (entities[i].yp <= -60)
|
|
|
|
{
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
if (game.roomy == 108)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
if (entities[i].yp <= 60)
|
|
|
|
{
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
//collector for factory
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
break;
|
|
|
|
case 14: //Very special hack: as two, but doesn't move in specific circumstances
|
|
|
|
if (entities[i].state == 0) //Init
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
for (size_t j = 0; j < entities.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[j].type == 2 && entities[j].state== 3 && entities[j].xp == (entities[i].xp-32) )
|
|
|
|
{
|
|
|
|
entities[i].state = 3;
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
bool entitygone = updateentities(i);
|
|
|
|
if (entitygone) return true;
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (entities[i].state == 1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[i].outside()) entities[i].state = entities[i].onwall;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (entities[i].state == 2)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].vx = entities[i].para;
|
|
|
|
entities[i].onwall = 3;
|
|
|
|
entities[i].state = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (entities[i].state == 3)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].vx = -entities[i].para;
|
|
|
|
entities[i].onwall = 2;
|
|
|
|
entities[i].state = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
case 15: //As above, but for 3!
|
|
|
|
if (entities[i].state == 0) //Init
|
|
|
|
{
|
|
|
|
for (size_t j = 0; j < entities.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[j].type == 2 && entities[j].state==3 && entities[j].xp==entities[i].xp+32)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].state = 3;
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
bool entitygone = updateentities(i);
|
|
|
|
if (entitygone) return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
if (entities[i].outside()) entities[i].state = entities[i].onwall;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
else if (entities[i].state == 2)
|
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].vx = -entities[i].para;
|
|
|
|
entities[i].onwall = 3;
|
|
|
|
entities[i].state = 1;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 3)
|
|
|
|
{
|
|
|
|
entities[i].vx = entities[i].para;
|
|
|
|
entities[i].onwall = 2;
|
|
|
|
entities[i].state = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 16: //MAVERICK BUS FOLLOWS HIS OWN RULES
|
|
|
|
if (entities[i].state == 0) //Init
|
|
|
|
{
|
2020-06-13 05:36:08 +02:00
|
|
|
int player = getplayer();
|
2020-04-03 22:57:02 +02:00
|
|
|
//first, y position
|
2020-06-13 05:36:08 +02:00
|
|
|
if (player > -1 && entities[player].yp > 14 * 8)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].tile = 120;
|
|
|
|
entities[i].yp = (28*8)-62;
|
2020-04-29 01:17:10 +02:00
|
|
|
entities[i].oldyp = (28*8)-62;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].tile = 96;
|
|
|
|
entities[i].yp = 24;
|
2020-04-29 01:17:10 +02:00
|
|
|
entities[i].oldyp = 24;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
//now, x position
|
2020-06-13 05:36:08 +02:00
|
|
|
if (player > -1 && entities[player].xp > 20 * 8)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//approach from the left
|
|
|
|
entities[i].xp = -64;
|
2020-04-29 01:17:10 +02:00
|
|
|
entities[i].oldxp = -64;
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].state = 2;
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
bool entitygone = updateentities(i); //right
|
|
|
|
if (entitygone) return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//approach from the left
|
|
|
|
entities[i].xp = 320;
|
2020-04-29 01:17:10 +02:00
|
|
|
entities[i].oldxp = 320;
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].state = 3;
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
bool entitygone = updateentities(i); //left
|
|
|
|
if (entitygone) return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (entities[i].state == 1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[i].outside()) entities[i].state = entities[i].onwall;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 2)
|
|
|
|
{
|
|
|
|
entities[i].vx = int(entities[i].para);
|
|
|
|
entities[i].onwall = 3;
|
|
|
|
entities[i].state = 1;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 3)
|
|
|
|
{
|
|
|
|
entities[i].vx = int(-entities[i].para);
|
|
|
|
entities[i].onwall = 2;
|
|
|
|
entities[i].state = 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 17: //Special for ASCII Snake (left)
|
|
|
|
if (entities[i].state == 0) //Init
|
|
|
|
{
|
|
|
|
entities[i].statedelay = 6;
|
|
|
|
entities[i].xp -= int(entities[i].para);
|
2020-05-02 02:40:14 +02:00
|
|
|
entities[i].oldxp -= int(entities[i].para);
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 18: //Special for ASCII Snake (right)
|
|
|
|
if (entities[i].state == 0) //Init
|
|
|
|
{
|
|
|
|
entities[i].statedelay = 6;
|
|
|
|
entities[i].xp += int(entities[i].para);
|
2020-05-02 02:40:14 +02:00
|
|
|
entities[i].oldxp += int(entities[i].para);
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 2: //Disappearing platforms
|
|
|
|
//wait for collision
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
entities[i].life = 12;
|
|
|
|
entities[i].state = 2;
|
|
|
|
entities[i].onentity = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
music.playef(7);
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 2)
|
|
|
|
{
|
|
|
|
entities[i].life--;
|
|
|
|
if (entities[i].life % 3 == 0) entities[i].tile++;
|
|
|
|
if (entities[i].life <= 0)
|
|
|
|
{
|
|
|
|
removeblockat(entities[i].xp, entities[i].yp);
|
|
|
|
entities[i].state = 3;// = false;
|
|
|
|
entities[i].invis = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
else if (entities[i].state == 3)
|
|
|
|
{
|
|
|
|
//wait until recharged!
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 4)
|
|
|
|
{
|
|
|
|
//restart!
|
|
|
|
createblock(0, entities[i].xp, entities[i].yp, 32, 8);
|
|
|
|
entities[i].state = 4;
|
|
|
|
entities[i].invis = false;
|
|
|
|
entities[i].tile--;
|
|
|
|
entities[i].state++;
|
|
|
|
entities[i].onentity = 1;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 5)
|
|
|
|
{
|
|
|
|
entities[i].life+=3;
|
|
|
|
if (entities[i].life % 3 == 0) entities[i].tile--;
|
|
|
|
if (entities[i].life >= 12)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].life = 12;
|
|
|
|
entities[i].state = 0;
|
|
|
|
entities[i].tile++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 3: //Breakable blocks
|
|
|
|
//Only counts if vy of player entity is non zero
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
entities[i].life = 4;
|
|
|
|
entities[i].state = 2;
|
|
|
|
entities[i].onentity = 0;
|
|
|
|
music.playef(6);
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 2)
|
|
|
|
{
|
|
|
|
entities[i].life--;
|
|
|
|
entities[i].tile++;
|
|
|
|
if (entities[i].life <= 0)
|
|
|
|
{
|
|
|
|
removeblockat(entities[i].xp, entities[i].yp);
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 4: //Gravity token
|
|
|
|
//wait for collision
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
game.gravitycontrol = (game.gravitycontrol + 1) % 2;
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 5: //Particle sprays
|
|
|
|
if (entities[i].state == 0)
|
|
|
|
{
|
|
|
|
entities[i].life--;
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
if (entities[i].life < 0)
|
|
|
|
{
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 6: //Small pickup
|
|
|
|
//wait for collision
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
music.playef(4);
|
2020-04-09 08:56:36 +02:00
|
|
|
collect[entities[i].para] = true;
|
2020-04-03 22:57:02 +02: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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 7: //Found a trinket
|
|
|
|
//wait for collision
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
Prevent out-of-bounds indexing with trinket/crewmate IDs
If a trinket or crewmate ID is out-of-bounds, it will not be created.
This is not only because the `collect`/`customcollect` check in
entityclass::createentity() would then be out-of-bounds, but also
touching it would also be out-of-bounds, too.
Display trinkets will always be created if the ID is out-of-bounds.
Apparently some people (@AllyTally) have been creating display trinkets
with IDs of -1 in order to get a display trinket that always shows up,
which is rather horrifying. But it makes sense, there's a lot more
nonzero int values than there are the amount of int values that are
zero, so it's fairly likely that the `collect` check will always come up
to be true (nonzero). Also, it's more useful to be able to have a
display trinket that always shows up without having to collect a trinket
beforehand, than it is to have it not be created (because technically by
default, you're already in the world where you don't have it created).
Display trinkets still have their `para` set to their ID, though, and if
they managed to gain an `onentity` of 1, bad things could happen... So
just to be sure, I added INBOUNDS checks to crewmates and trinkets in
entityclass::updateentities() so no UB will happen if you collect a
crewmate/trinket with an out-of-bounds ID. Also, I de-duplicated the
`collect`/`customcollect` setting, too.
2020-06-15 23:20:37 +02:00
|
|
|
if (INBOUNDS(entities[i].para, collect))
|
2020-04-03 22:57:02 +02:00
|
|
|
{
|
2020-04-09 08:56:36 +02:00
|
|
|
collect[entities[i].para] = true;
|
Prevent out-of-bounds indexing with trinket/crewmate IDs
If a trinket or crewmate ID is out-of-bounds, it will not be created.
This is not only because the `collect`/`customcollect` check in
entityclass::createentity() would then be out-of-bounds, but also
touching it would also be out-of-bounds, too.
Display trinkets will always be created if the ID is out-of-bounds.
Apparently some people (@AllyTally) have been creating display trinkets
with IDs of -1 in order to get a display trinket that always shows up,
which is rather horrifying. But it makes sense, there's a lot more
nonzero int values than there are the amount of int values that are
zero, so it's fairly likely that the `collect` check will always come up
to be true (nonzero). Also, it's more useful to be able to have a
display trinket that always shows up without having to collect a trinket
beforehand, than it is to have it not be created (because technically by
default, you're already in the world where you don't have it created).
Display trinkets still have their `para` set to their ID, though, and if
they managed to gain an `onentity` of 1, bad things could happen... So
just to be sure, I added INBOUNDS checks to crewmates and trinkets in
entityclass::updateentities() so no UB will happen if you collect a
crewmate/trinket with an out-of-bounds ID. Also, I de-duplicated the
`collect`/`customcollect` setting, too.
2020-06-15 23:20:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (game.intimetrial)
|
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
music.playef(25);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
game.state = 1000;
|
|
|
|
if(music.currentsong!=-1) music.silencedasmusik();
|
|
|
|
music.playef(3);
|
2020-04-07 08:46:27 +02:00
|
|
|
if (game.trinkets() > game.stat_trinkets && !map.custommode)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-07 08:46:27 +02:00
|
|
|
game.stat_trinkets = game.trinkets();
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 8: //Savepoints
|
|
|
|
//wait for collision
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
//First, deactivate all other savepoints
|
|
|
|
for (size_t j = 0; j < entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (entities[j].type == 8)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[j].colour = 4;
|
|
|
|
entities[j].onentity = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].colour = 5;
|
|
|
|
entities[i].onentity = 0;
|
|
|
|
game.savepoint = entities[i].para;
|
|
|
|
music.playef(5);
|
|
|
|
|
|
|
|
game.savex = entities[i].xp - 4;
|
|
|
|
|
|
|
|
if (entities[i].tile == 20)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
game.savey = entities[i].yp - 1;
|
|
|
|
game.savegc = 1;
|
|
|
|
}
|
|
|
|
else if (entities[i].tile == 21)
|
|
|
|
{
|
|
|
|
game.savey = entities[i].yp-8;
|
|
|
|
game.savegc = 0;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
game.saverx = game.roomx;
|
|
|
|
game.savery = game.roomy;
|
2020-06-13 05:36:08 +02:00
|
|
|
int player = getplayer();
|
|
|
|
if (player > -1)
|
|
|
|
{
|
|
|
|
game.savedir = entities[player].dir;
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].state = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 9: //Gravity Lines
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
entities[i].life--;
|
|
|
|
entities[i].onentity = 0;
|
|
|
|
|
|
|
|
if (entities[i].life <= 0)
|
|
|
|
{
|
|
|
|
entities[i].state = 0;
|
|
|
|
entities[i].onentity = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 10: //Vertical gravity Lines
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
entities[i].onentity = 3;
|
|
|
|
entities[i].state = 2;
|
|
|
|
|
|
|
|
|
|
|
|
music.playef(8);
|
|
|
|
game.gravitycontrol = (game.gravitycontrol + 1) % 2;
|
|
|
|
game.totalflips++;
|
|
|
|
temp = getplayer();
|
|
|
|
if (game.gravitycontrol == 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-06-13 05:36:08 +02:00
|
|
|
if (temp > -1 && entities[temp].vy < 3) entities[temp].vy = 3;
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-06-13 05:36:08 +02:00
|
|
|
if (temp > -1 && entities[temp].vy > -3) entities[temp].vy = -3;
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 2)
|
|
|
|
{
|
|
|
|
entities[i].life--;
|
|
|
|
if (entities[i].life <= 0)
|
|
|
|
{
|
|
|
|
entities[i].state = 0;
|
|
|
|
entities[i].onentity = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 3)
|
|
|
|
{
|
|
|
|
entities[i].state = 2;
|
|
|
|
entities[i].life = 4;
|
|
|
|
entities[i].onentity = 3;
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 4)
|
|
|
|
{
|
|
|
|
//Special case for room initilisations: As state one, except without the reversal
|
|
|
|
entities[i].onentity = 3;
|
|
|
|
entities[i].state = 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 11: //Warp point
|
|
|
|
//wait for collision
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
//Depending on the room the warp point is in, teleport to a new location!
|
|
|
|
entities[i].onentity = 0;
|
|
|
|
//play a sound or somefink
|
|
|
|
music.playef(10);
|
|
|
|
game.teleport = true;
|
|
|
|
|
|
|
|
game.edteleportent = i;
|
|
|
|
//for the multiple room:
|
|
|
|
if (int(entities[i].xp) == 12*8) game.teleportxpos = 1;
|
|
|
|
if (int(entities[i].xp) == 5*8) game.teleportxpos = 2;
|
|
|
|
if (int(entities[i].xp) == 28*8) game.teleportxpos = 3;
|
|
|
|
if (int(entities[i].xp) == 21*8) game.teleportxpos = 4;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 12: //Crew member
|
|
|
|
//Somewhat complex AI: exactly what they do depends on room, location, state etc
|
|
|
|
//At state 0, do nothing at all.
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
//happy!
|
|
|
|
if (entities[k].rule == 6) entities[k].tile = 0;
|
|
|
|
if (entities[k].rule == 7) entities[k].tile = 6;
|
|
|
|
//Stay close to the hero!
|
|
|
|
int j = getplayer();
|
2020-06-13 05:36:08 +02:00
|
|
|
if (j > -1 && entities[j].xp > entities[i].xp + 5)
|
2020-04-03 22:57:02 +02:00
|
|
|
{
|
|
|
|
entities[i].dir = 1;
|
|
|
|
}
|
2020-06-13 05:36:08 +02:00
|
|
|
else if (j > -1 && entities[j].xp < entities[i].xp - 5)
|
2020-04-03 22:57:02 +02:00
|
|
|
{
|
|
|
|
entities[i].dir = 0;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-06-13 05:36:08 +02:00
|
|
|
if (j > -1 && entities[j].xp > entities[i].xp + 45)
|
2020-04-03 22:57:02 +02:00
|
|
|
{
|
|
|
|
entities[i].ax = 3;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-06-13 05:36:08 +02:00
|
|
|
else if (j > -1 && entities[j].xp < entities[i].xp - 45)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].ax = -3;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
//Special rules:
|
|
|
|
if (game.roomx == 110 && game.roomy == 105)
|
|
|
|
{
|
|
|
|
if (entities[i].xp < 155)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[i].ax < 0) entities[i].ax = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
else if (entities[i].state == 2)
|
|
|
|
{
|
|
|
|
//Basic rules, don't change expression
|
|
|
|
int j = getplayer();
|
2020-06-13 05:36:08 +02:00
|
|
|
if (j > -1 && entities[j].xp > entities[i].xp + 5)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].dir = 1;
|
|
|
|
}
|
2020-06-13 05:36:08 +02:00
|
|
|
else if (j > -1 && entities[j].xp < entities[i].xp - 5)
|
2020-04-03 22:57:02 +02:00
|
|
|
{
|
|
|
|
entities[i].dir = 0;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-06-13 05:36:08 +02:00
|
|
|
if (j > -1 && entities[j].xp > entities[i].xp + 45)
|
2020-04-03 22:57:02 +02:00
|
|
|
{
|
|
|
|
entities[i].ax = 3;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-06-13 05:36:08 +02:00
|
|
|
else if (j > -1 && entities[j].xp < entities[i].xp - 45)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].ax = -3;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
else if (entities[i].state == 10)
|
|
|
|
{
|
|
|
|
//Everything from 10 on is for cutscenes
|
|
|
|
//Basic rules, don't change expression
|
|
|
|
int j = getplayer();
|
2020-06-13 05:36:08 +02:00
|
|
|
if (j > -1 && entities[j].xp > entities[i].xp + 5)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].dir = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-06-13 05:36:08 +02:00
|
|
|
else if (j > -1 && entities[j].xp < entities[i].xp - 5)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].dir = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
|
2020-06-13 05:36:08 +02:00
|
|
|
if (j > -1 && entities[j].xp > entities[i].xp + 45)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].ax = 3;
|
|
|
|
}
|
2020-06-13 05:36:08 +02:00
|
|
|
else if (j > -1 && entities[j].xp < entities[i].xp - 45)
|
2020-04-03 22:57:02 +02:00
|
|
|
{
|
|
|
|
entities[i].ax = -3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 11)
|
|
|
|
{
|
|
|
|
//11-15 means to follow a specific character, in crew order (cyan, purple, yellow, red, green, blue)
|
|
|
|
int j=getcrewman(1); //purple
|
|
|
|
if (entities[j].xp > entities[i].xp + 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 1;
|
|
|
|
}
|
|
|
|
else if (entities[j].xp < entities[i].xp - 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 0;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[j].xp > entities[i].xp + 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = 3;
|
|
|
|
}
|
|
|
|
else if (entities[j].xp < entities[i].xp - 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = -3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 12)
|
|
|
|
{
|
|
|
|
//11-15 means to follow a specific character, in crew order (cyan, purple, yellow, red, green, blue)
|
|
|
|
int j=getcrewman(2); //yellow
|
|
|
|
if (entities[j].xp > entities[i].xp + 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 1;
|
|
|
|
}
|
|
|
|
else if (entities[j].xp < entities[i].xp - 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 0;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[j].xp > entities[i].xp + 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = 3;
|
|
|
|
}
|
|
|
|
else if (entities[j].xp < entities[i].xp - 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = -3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 13)
|
|
|
|
{
|
|
|
|
//11-15 means to follow a specific character, in crew order (cyan, purple, yellow, red, green, blue)
|
|
|
|
int j=getcrewman(3); //red
|
|
|
|
if (entities[j].xp > entities[i].xp + 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 1;
|
|
|
|
}
|
|
|
|
else if (entities[j].xp < entities[i].xp - 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entities[j].xp > entities[i].xp + 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = 3;
|
|
|
|
}
|
|
|
|
else if (entities[j].xp < entities[i].xp - 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = -3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 14)
|
|
|
|
{
|
|
|
|
//11-15 means to follow a specific character, in crew order (cyan, purple, yellow, red, green, blue)
|
|
|
|
int j=getcrewman(4); //green
|
|
|
|
if (entities[j].xp > entities[i].xp + 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 1;
|
|
|
|
}
|
|
|
|
else if (entities[j].xp < entities[i].xp - 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entities[j].xp > entities[i].xp + 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = 3;
|
|
|
|
}
|
|
|
|
else if (entities[j].xp < entities[i].xp - 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = -3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 15)
|
|
|
|
{
|
|
|
|
//11-15 means to follow a specific character, in crew order (cyan, purple, yellow, red, green, blue)
|
|
|
|
int j=getcrewman(5); //blue
|
|
|
|
if (entities[j].xp > entities[i].xp + 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 1;
|
|
|
|
}
|
|
|
|
else if (entities[j].xp < entities[i].xp - 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entities[j].xp > entities[i].xp + 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = 3;
|
|
|
|
}
|
|
|
|
else if (entities[j].xp < entities[i].xp - 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = -3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 16)
|
|
|
|
{
|
|
|
|
//Follow a position: given an x coordinate, seek it out.
|
|
|
|
if (entities[i].para > entities[i].xp + 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 1;
|
|
|
|
}
|
|
|
|
else if (entities[i].para < entities[i].xp - 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entities[i].para > entities[i].xp + 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = 3;
|
|
|
|
}
|
|
|
|
else if (entities[i].para < entities[i].xp - 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = -3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 17)
|
|
|
|
{
|
|
|
|
//stand still
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 18)
|
|
|
|
{
|
|
|
|
//Stand still and face the player
|
|
|
|
int j = getplayer();
|
2020-06-13 05:36:08 +02:00
|
|
|
if (j > -1 && entities[j].xp > entities[i].xp + 5)
|
2020-04-03 22:57:02 +02:00
|
|
|
{
|
|
|
|
entities[i].dir = 1;
|
|
|
|
}
|
2020-06-13 05:36:08 +02:00
|
|
|
else if (j > -1 && entities[j].xp < entities[i].xp - 5)
|
2020-04-03 22:57:02 +02:00
|
|
|
{
|
|
|
|
entities[i].dir = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 19)
|
|
|
|
{
|
|
|
|
//Walk right off the screen after time t
|
|
|
|
if (entities[i].para <= 0)
|
|
|
|
{
|
|
|
|
entities[i].dir = 1;
|
|
|
|
entities[i].ax = 3;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].para--;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
else if (entities[i].state == 20)
|
|
|
|
{
|
|
|
|
//Panic! For briefing script
|
|
|
|
if (entities[i].life == 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//walk left for a bit
|
|
|
|
entities[i].ax = 0;
|
|
|
|
if (40 > entities[i].xp + 5)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].dir = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (40 < entities[i].xp - 5)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].dir = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
if (40 > entities[i].xp + 45)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
entities[i].ax = 3;
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (40 < entities[i].xp - 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = -3;
|
|
|
|
}
|
|
|
|
if ( (entities[i].ax) == 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].life = 1;
|
|
|
|
entities[i].para = 30;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (entities[i].life == 1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//Stand around for a bit
|
|
|
|
entities[i].para--;
|
|
|
|
if (entities[i].para <= 0)
|
|
|
|
{
|
|
|
|
entities[i].life++;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (entities[i].life == 2)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//walk right for a bit
|
|
|
|
entities[i].ax = 0;
|
|
|
|
if (280 > entities[i].xp + 5)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].dir = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (280 < entities[i].xp - 5)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].dir = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
if (280 > entities[i].xp + 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = 3;
|
|
|
|
}
|
|
|
|
else if (280 < entities[i].xp - 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = -3;
|
|
|
|
}
|
|
|
|
if ( (entities[i].ax) == 0)
|
|
|
|
{
|
|
|
|
entities[i].life = 3;
|
|
|
|
entities[i].para = 30;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (entities[i].life == 3)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//Stand around for a bit
|
|
|
|
entities[i].para--;
|
|
|
|
if (entities[i].para <= 0)
|
|
|
|
{
|
|
|
|
entities[i].life=0;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 13: //Terminals (very similar to savepoints)
|
|
|
|
//wait for collision
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
entities[i].colour = 5;
|
|
|
|
entities[i].onentity = 0;
|
|
|
|
music.playef(17);
|
|
|
|
|
|
|
|
entities[i].state = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 14: //Super Crew member
|
|
|
|
//Actually needs less complex AI than the scripting crewmember
|
|
|
|
if (entities[i].state == 0)
|
|
|
|
{
|
|
|
|
//follow player, but only if he's on the floor!
|
|
|
|
int j = getplayer();
|
2020-06-13 05:36:08 +02:00
|
|
|
if(j > -1 && entities[j].onground>0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (entities[j].xp > entities[i].xp + 5)
|
|
|
|
{
|
|
|
|
entities[i].dir = 1;
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (entities[j].xp>15 && entities[j].xp < entities[i].xp - 5)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
entities[i].dir = 0;
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
|
|
|
|
if (entities[j].xp > entities[i].xp + 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = 3;
|
|
|
|
}
|
|
|
|
else if (entities[j].xp < entities[i].xp - 45)
|
|
|
|
{
|
|
|
|
entities[i].ax = -3;
|
|
|
|
}
|
|
|
|
if (entities[i].ax < 0 && entities[i].xp < 60)
|
|
|
|
{
|
|
|
|
entities[i].ax = 0;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-06-13 05:36:08 +02:00
|
|
|
if (j > -1 && entities[j].xp > entities[i].xp + 5)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].dir = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-06-13 05:36:08 +02:00
|
|
|
else if (j > -1 && entities[j].xp < entities[i].xp - 5)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].dir = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].ax = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (entities[i].xp > 240)
|
|
|
|
{
|
|
|
|
entities[i].ax = 3;
|
|
|
|
entities[i].dir = 1;
|
|
|
|
}
|
|
|
|
if (entities[i].xp >= 310)
|
|
|
|
{
|
|
|
|
game.scmprogress++;
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 15: //Trophy
|
|
|
|
//wait for collision
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
trophytext+=2;
|
|
|
|
if (trophytext > 30) trophytext = 30;
|
|
|
|
trophytype = entities[i].para;
|
|
|
|
|
|
|
|
entities[i].state = 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 23:
|
|
|
|
//swn game!
|
|
|
|
switch(entities[i].behave)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
if (entities[i].state == 0) //Init
|
|
|
|
{
|
|
|
|
entities[i].vx = 7;
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
if (entities[i].xp > 320)
|
|
|
|
{
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
case 1:
|
|
|
|
if (entities[i].state == 0) //Init
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].vx = -7;
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
if (entities[i].xp <-20)
|
|
|
|
{
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
case 51: //Vertical warp line
|
|
|
|
if (entities[i].state == 2){
|
|
|
|
int j=getplayer();
|
2020-06-13 05:36:08 +02:00
|
|
|
if(j > -1 && entities[j].xp<=307){
|
2020-04-03 22:57:02 +02:00
|
|
|
customwarpmodevon=false;
|
|
|
|
entities[i].state = 0;
|
|
|
|
}
|
|
|
|
}else if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
entities[i].state = 2;
|
|
|
|
entities[i].statedelay = 2;
|
|
|
|
entities[i].onentity = 1;
|
|
|
|
customwarpmodevon=true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 52: //Vertical warp line
|
|
|
|
if (entities[i].state == 2){
|
|
|
|
int j=getplayer();
|
2020-06-13 05:36:08 +02:00
|
|
|
if(j > -1 && entities[j].xp<=307){
|
2020-04-03 22:57:02 +02:00
|
|
|
customwarpmodevon=false;
|
|
|
|
entities[i].state = 0;
|
|
|
|
}
|
|
|
|
}else if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
entities[i].state = 2;
|
|
|
|
entities[i].statedelay = 2;
|
|
|
|
entities[i].onentity = 1;
|
|
|
|
customwarpmodevon=true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 53: //Warp lines Horizonal
|
|
|
|
if (entities[i].state == 2){
|
|
|
|
customwarpmodehon=false;
|
|
|
|
entities[i].state = 0;
|
|
|
|
}else if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
entities[i].state = 2;
|
|
|
|
entities[i].statedelay = 2;
|
|
|
|
entities[i].onentity = 1;
|
|
|
|
customwarpmodehon=true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 54: //Warp lines Horizonal
|
|
|
|
if (entities[i].state == 2){
|
|
|
|
customwarpmodehon=false;
|
|
|
|
entities[i].state = 0;
|
|
|
|
}else if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
entities[i].state = 2;
|
|
|
|
entities[i].statedelay = 2;
|
|
|
|
entities[i].onentity = 1;
|
|
|
|
customwarpmodehon=true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 55: //Collectable crewmate
|
|
|
|
//wait for collision
|
|
|
|
if (entities[i].state == 0)
|
|
|
|
{
|
|
|
|
//Basic rules, don't change expression
|
|
|
|
int j = getplayer();
|
2020-06-13 05:36:08 +02:00
|
|
|
if (j > -1 && entities[j].xp > entities[i].xp + 5)
|
2020-04-03 22:57:02 +02:00
|
|
|
{
|
|
|
|
entities[i].dir = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-06-13 05:36:08 +02:00
|
|
|
else if (j > -1 && entities[j].xp < entities[i].xp - 5)
|
2020-04-03 22:57:02 +02:00
|
|
|
{
|
|
|
|
entities[i].dir = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entities[i].state == 1)
|
|
|
|
{
|
Prevent out-of-bounds indexing with trinket/crewmate IDs
If a trinket or crewmate ID is out-of-bounds, it will not be created.
This is not only because the `collect`/`customcollect` check in
entityclass::createentity() would then be out-of-bounds, but also
touching it would also be out-of-bounds, too.
Display trinkets will always be created if the ID is out-of-bounds.
Apparently some people (@AllyTally) have been creating display trinkets
with IDs of -1 in order to get a display trinket that always shows up,
which is rather horrifying. But it makes sense, there's a lot more
nonzero int values than there are the amount of int values that are
zero, so it's fairly likely that the `collect` check will always come up
to be true (nonzero). Also, it's more useful to be able to have a
display trinket that always shows up without having to collect a trinket
beforehand, than it is to have it not be created (because technically by
default, you're already in the world where you don't have it created).
Display trinkets still have their `para` set to their ID, though, and if
they managed to gain an `onentity` of 1, bad things could happen... So
just to be sure, I added INBOUNDS checks to crewmates and trinkets in
entityclass::updateentities() so no UB will happen if you collect a
crewmate/trinket with an out-of-bounds ID. Also, I de-duplicated the
`collect`/`customcollect` setting, too.
2020-06-15 23:20:37 +02:00
|
|
|
if (INBOUNDS(entities[i].para, customcollect))
|
2020-04-03 22:57:02 +02:00
|
|
|
{
|
2020-04-09 08:58:03 +02:00
|
|
|
customcollect[entities[i].para] = true;
|
Prevent out-of-bounds indexing with trinket/crewmate IDs
If a trinket or crewmate ID is out-of-bounds, it will not be created.
This is not only because the `collect`/`customcollect` check in
entityclass::createentity() would then be out-of-bounds, but also
touching it would also be out-of-bounds, too.
Display trinkets will always be created if the ID is out-of-bounds.
Apparently some people (@AllyTally) have been creating display trinkets
with IDs of -1 in order to get a display trinket that always shows up,
which is rather horrifying. But it makes sense, there's a lot more
nonzero int values than there are the amount of int values that are
zero, so it's fairly likely that the `collect` check will always come up
to be true (nonzero). Also, it's more useful to be able to have a
display trinket that always shows up without having to collect a trinket
beforehand, than it is to have it not be created (because technically by
default, you're already in the world where you don't have it created).
Display trinkets still have their `para` set to their ID, though, and if
they managed to gain an `onentity` of 1, bad things could happen... So
just to be sure, I added INBOUNDS checks to crewmates and trinkets in
entityclass::updateentities() so no UB will happen if you collect a
crewmate/trinket with an out-of-bounds ID. Also, I de-duplicated the
`collect`/`customcollect` setting, too.
2020-06-15 23:20:37 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (game.intimetrial)
|
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
music.playef(27);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
game.state = 1010;
|
|
|
|
//music.haltdasmusik();
|
|
|
|
if(music.currentsong!=-1) music.silencedasmusik();
|
|
|
|
music.playef(27);
|
|
|
|
}
|
|
|
|
|
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);'.
2020-06-13 21:00:04 +02:00
|
|
|
return removeentity(i);
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 100: //The teleporter
|
|
|
|
if (entities[i].state == 1)
|
|
|
|
{
|
|
|
|
//if inactive, activate!
|
|
|
|
if (entities[i].tile == 1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
music.playef(18);
|
2020-01-01 21:29:24 +01:00
|
|
|
entities[i].onentity = 0;
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[i].tile = 2;
|
|
|
|
entities[i].colour = 101;
|
|
|
|
if(!game.intimetrial && !game.nodeathmode)
|
|
|
|
{
|
|
|
|
game.state = 2000;
|
|
|
|
game.statedelay = 0;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
|
|
|
game.activetele = true;
|
|
|
|
game.teleblock.x = entities[i].xp - 32;
|
|
|
|
game.teleblock.y = entities[i].yp - 32;
|
|
|
|
game.teleblock.w = 160;
|
|
|
|
game.teleblock.h = 160;
|
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
|
|
|
|
//Alright, let's set this as our savepoint too
|
|
|
|
//First, deactivate all other savepoints
|
|
|
|
for (size_t j = 0; j < entities.size(); j++)
|
|
|
|
{
|
|
|
|
if (entities[j].type == 8)
|
|
|
|
{
|
|
|
|
entities[j].colour = 4;
|
|
|
|
entities[j].onentity = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
game.savepoint = static_cast<int>(entities[i].para);
|
|
|
|
game.savex = entities[i].xp + 44;
|
|
|
|
game.savey = entities[i].yp + 44;
|
|
|
|
game.savegc = 0;
|
|
|
|
|
|
|
|
game.saverx = game.roomx;
|
|
|
|
game.savery = game.roomy;
|
2020-06-13 05:36:08 +02:00
|
|
|
int player = getplayer();
|
|
|
|
if (player > -1)
|
|
|
|
{
|
|
|
|
game.savedir = entities[player].dir;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
entities[i].state = 0;
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
|
|
|
|
entities[i].state = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else if (entities[i].state == 2)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//Initilise the teleporter without changing the game state or playing sound
|
|
|
|
entities[i].onentity = 0;
|
|
|
|
entities[i].tile = 6;
|
|
|
|
entities[i].colour = 102;
|
|
|
|
|
|
|
|
game.activetele = true;
|
|
|
|
game.teleblock.x = entities[i].xp - 32;
|
|
|
|
game.teleblock.y = entities[i].yp - 32;
|
|
|
|
game.teleblock.w = 160;
|
|
|
|
game.teleblock.h = 160;
|
|
|
|
|
|
|
|
entities[i].state = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[i].statedelay--;
|
|
|
|
if (entities[i].statedelay < 0)
|
|
|
|
{
|
|
|
|
entities[i].statedelay = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
Prevent updating an entity if updateentities() removed it
Otherwise, this would result in the game updating an entity twice, which
isn't good. This is most noticeable in the Gravitron, where many
Gravitron squares are created and destroyed at a time, and it's
especially noticeable during the part near the end of the Gravitron
where the pattern is two Gravitron squares, one at the top and bottom,
and then two Gravitron squares in the middle afterwards. The timing is
just right such that the top one of the two middle ones would be
misaligned with the bottom one of the two when a Gravitron square gets
outside the screen.
To do this, I changed entityclass::updateentities() into a bool, and
made every single caller check its return value. I only needed to do
this for the ones preceding updateentitylogic() and
entitymapcollision(), but I wanted to play it safe and be defensive, so
I did it for the disappearing platform kludge, as well as the
updateentities() within the updateentities() function.
2020-05-05 22:49:12 +02:00
|
|
|
|
|
|
|
return false;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
void entityclass::animateentities( int _i )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (_i < 0 || _i >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("animateentities() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
if(entities[_i].statedelay < 1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
switch(entities[_i].type)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
case 0:
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].dir==1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].drawframe=entities[_i].tile;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[_i].drawframe=entities[_i].tile+3;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
if(entities[_i].onground>0 || entities[_i].onroof>0)
|
|
|
|
{
|
|
|
|
if(entities[_i].vx > 0.00f || entities[_i].vx < -0.00f)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//Walking
|
|
|
|
if(entities[_i].framedelay<=1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].framedelay=4;
|
|
|
|
entities[_i].walkingframe++;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[_i].walkingframe >=2) entities[_i].walkingframe=0;
|
|
|
|
entities[_i].drawframe += entities[_i].walkingframe + 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[_i].onroof > 0) entities[_i].drawframe += 6;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[_i].drawframe ++;
|
|
|
|
if (game.gravitycontrol == 1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].drawframe += 6;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
if (game.deathseq > -1)
|
|
|
|
{
|
|
|
|
entities[_i].drawframe=13;
|
|
|
|
if (entities[_i].dir == 1) entities[_i].drawframe = 12;
|
|
|
|
if (game.gravitycontrol == 1) entities[_i].drawframe += 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
case 23:
|
|
|
|
//Variable animation
|
|
|
|
switch(entities[_i].animate)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
//Simple oscilation
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].framedelay<=0)
|
|
|
|
{
|
|
|
|
entities[_i].framedelay = 8;
|
|
|
|
if(entities[_i].actionframe==0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
entities[_i].walkingframe++;
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[_i].walkingframe == 4)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].walkingframe = 2;
|
|
|
|
entities[_i].actionframe = 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].walkingframe--;
|
|
|
|
if (entities[_i].walkingframe == -1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].walkingframe = 1;
|
|
|
|
entities[_i].actionframe = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
entities[_i].drawframe += entities[_i].walkingframe;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
//Simple Loop
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].framedelay<=0)
|
|
|
|
{
|
|
|
|
entities[_i].framedelay = 8;
|
|
|
|
entities[_i].walkingframe++;
|
|
|
|
if (entities[_i].walkingframe == 4)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].walkingframe = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
entities[_i].drawframe += entities[_i].walkingframe;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
//Simpler Loop (just two frames)
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].framedelay<=0)
|
|
|
|
{
|
|
|
|
entities[_i].framedelay = 2;
|
|
|
|
entities[_i].walkingframe++;
|
|
|
|
if (entities[_i].walkingframe == 2)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].walkingframe = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
entities[_i].drawframe += entities[_i].walkingframe;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
|
|
//Simpler Loop (just two frames, but double sized)
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].framedelay<=0)
|
|
|
|
{
|
|
|
|
entities[_i].framedelay = 2;
|
|
|
|
entities[_i].walkingframe++;
|
|
|
|
if (entities[_i].walkingframe == 2)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].walkingframe = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
entities[_i].drawframe += (entities[_i].walkingframe*2);
|
|
|
|
break;
|
|
|
|
case 4:
|
|
|
|
//Simpler Loop (just two frames, but double sized) (as above but slower)
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].framedelay<=0)
|
|
|
|
{
|
|
|
|
entities[_i].framedelay = 6;
|
|
|
|
entities[_i].walkingframe++;
|
|
|
|
if (entities[_i].walkingframe == 2)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].walkingframe = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].drawframe += (entities[_i].walkingframe*2);
|
|
|
|
break;
|
|
|
|
case 5:
|
|
|
|
//Simpler Loop (just two frames) (slower)
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].framedelay<=0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].framedelay = 6;
|
|
|
|
entities[_i].walkingframe++;
|
|
|
|
if (entities[_i].walkingframe == 2)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].walkingframe = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
|
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
entities[_i].drawframe += entities[_i].walkingframe;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
case 6:
|
|
|
|
//Normal Loop (four frames, double sized)
|
2020-01-01 21:29:24 +01:00
|
|
|
entities[_i].framedelay--;
|
2020-04-03 22:57:02 +02:00
|
|
|
if(entities[_i].framedelay<=0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].framedelay = 4;
|
|
|
|
entities[_i].walkingframe++;
|
|
|
|
if (entities[_i].walkingframe == 4)
|
|
|
|
{
|
|
|
|
entities[_i].walkingframe = 0;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
entities[_i].drawframe += (entities[_i].walkingframe*2);
|
|
|
|
break;
|
|
|
|
case 7:
|
|
|
|
//Simpler Loop (just two frames) (slower) (with directions!)
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].framedelay<=0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].framedelay = 6;
|
|
|
|
entities[_i].walkingframe++;
|
|
|
|
if (entities[_i].walkingframe == 2)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].walkingframe = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
|
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
entities[_i].drawframe += entities[_i].walkingframe;
|
|
|
|
|
|
|
|
if (entities[_i].vx > 0.000f ) entities[_i].drawframe += 2;
|
|
|
|
break;
|
|
|
|
case 10:
|
|
|
|
//Threadmill left
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].framedelay<=0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].framedelay = 3;//(6-entities[_i].para);
|
|
|
|
entities[_i].walkingframe--;
|
|
|
|
if (entities[_i].walkingframe == -1)
|
|
|
|
{
|
|
|
|
entities[_i].walkingframe = 3;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
entities[_i].drawframe += entities[_i].walkingframe;
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
//Threadmill right
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].framedelay<=0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].framedelay = 3;//(6-entities[_i].para);
|
|
|
|
entities[_i].walkingframe++;
|
|
|
|
if (entities[_i].walkingframe == 4)
|
|
|
|
{
|
|
|
|
entities[_i].walkingframe = 0;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
|
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
entities[_i].drawframe += entities[_i].walkingframe;
|
|
|
|
break;
|
|
|
|
case 100:
|
|
|
|
//Simple case for no animation (platforms, etc)
|
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
2020-01-01 21:29:24 +01:00
|
|
|
break;
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 11:
|
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
if(entities[_i].animate==2)
|
|
|
|
{
|
|
|
|
//Simpler Loop (just two frames)
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].framedelay<=0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].framedelay = 10;
|
|
|
|
entities[_i].walkingframe++;
|
|
|
|
if (entities[_i].walkingframe == 2)
|
|
|
|
{
|
|
|
|
entities[_i].walkingframe = 0;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
entities[_i].drawframe += entities[_i].walkingframe;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 12:
|
|
|
|
case 55:
|
|
|
|
case 14: //Crew member! Very similar to hero
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].dir==1)
|
|
|
|
{
|
|
|
|
entities[_i].drawframe=entities[_i].tile;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[_i].drawframe=entities[_i].tile+3;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(entities[_i].onground>0 || entities[_i].onroof>0)
|
|
|
|
{
|
|
|
|
if(entities[_i].vx > 0.0000f || entities[_i].vx < -0.000f)
|
|
|
|
{
|
|
|
|
//Walking
|
2020-01-01 21:29:24 +01:00
|
|
|
if(entities[_i].framedelay<=0)
|
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].framedelay=4;
|
|
|
|
entities[_i].walkingframe++;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[_i].walkingframe >=2) entities[_i].walkingframe=0;
|
|
|
|
entities[_i].drawframe += entities[_i].walkingframe + 1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
//if (entities[_i].onroof > 0) entities[_i].drawframe += 6;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[_i].drawframe ++;
|
|
|
|
//if (game.gravitycontrol == 1) {
|
|
|
|
// entities[_i].drawframe += 6;
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (game.deathseq > -1)
|
|
|
|
{
|
|
|
|
entities[_i].drawframe=13;
|
|
|
|
if (entities[_i].dir == 1) entities[_i].drawframe = 12;
|
|
|
|
if (entities[_i].rule == 7) entities[_i].drawframe += 2;
|
|
|
|
//if (game.gravitycontrol == 1) entities[_i].drawframe += 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 100: //the teleporter!
|
|
|
|
if (entities[_i].tile == 1)
|
|
|
|
{
|
|
|
|
//it's inactive
|
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
}
|
|
|
|
else if (entities[_i].tile == 2)
|
|
|
|
{
|
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
|
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].framedelay<=0)
|
|
|
|
{
|
|
|
|
entities[_i].framedelay = 1;
|
|
|
|
entities[_i].walkingframe = int(fRandom() * 6);
|
|
|
|
if (entities[_i].walkingframe >= 4)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].walkingframe = -1;
|
|
|
|
entities[_i].framedelay = 4;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
entities[_i].drawframe += entities[_i].walkingframe;
|
|
|
|
}
|
|
|
|
else if (entities[_i].tile == 6)
|
|
|
|
{
|
|
|
|
//faster!
|
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].framedelay--;
|
|
|
|
if(entities[_i].framedelay<=0)
|
|
|
|
{
|
|
|
|
entities[_i].framedelay = 2;
|
|
|
|
entities[_i].walkingframe = int(fRandom() * 6);
|
|
|
|
if (entities[_i].walkingframe >= 4)
|
|
|
|
{
|
|
|
|
entities[_i].walkingframe = -5;
|
|
|
|
entities[_i].framedelay = 4;
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[_i].drawframe += entities[_i].walkingframe;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
entities[_i].drawframe = entities[_i].tile;
|
|
|
|
break;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//entities[_i].statedelay--;
|
|
|
|
if (entities[_i].statedelay < 0) entities[_i].statedelay = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-02 00:32:21 +02:00
|
|
|
int entityclass::getcompanion()
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//Returns the index of the companion with rule t
|
2020-04-03 22:50:16 +02:00
|
|
|
for (size_t i = 0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if(entities[i].rule==6 || entities[i].rule==7)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int entityclass::getplayer()
|
|
|
|
{
|
|
|
|
//Returns the index of the first player entity
|
2020-04-03 22:50:16 +02:00
|
|
|
for (size_t i = 0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if(entities[i].type==0)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int entityclass::getscm()
|
|
|
|
{
|
|
|
|
//Returns the supercrewmate
|
2020-04-03 22:50:16 +02:00
|
|
|
for (size_t i = 0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if(entities[i].type==14)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int entityclass::getlineat( int t )
|
|
|
|
{
|
|
|
|
//Get the entity which is a horizontal line at height t (for SWN game)
|
2020-04-03 22:50:16 +02:00
|
|
|
for (size_t i = 0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (entities[i].size == 5)
|
|
|
|
{
|
|
|
|
if (entities[i].yp == t)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int entityclass::getcrewman( int t )
|
|
|
|
{
|
|
|
|
//Returns the index of the crewman with colour index given by t
|
|
|
|
if (t == 0) t = 0;
|
|
|
|
if (t == 1) t = 20;
|
|
|
|
if (t == 2) t = 14;
|
|
|
|
if (t == 3) t = 15;
|
|
|
|
if (t == 4) t = 13;
|
|
|
|
if (t == 5) t = 16;
|
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
for (size_t i = 0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
Prevent the game from thinking horizontal warp lines are cyan crewmates (#87)
* Add entity type attribute checks to getcrewman()
This means that the game is no longer able to target other non-crewmate
entities when it looks for a crewmate.
This has actually happened in practice. A command like
position(cyan,above) could position the text box above a horizontal warp
line instead of the intended crewmate.
This is because getcrewman() previously only checked the rule attributes
of entities, and if their rule happened to be 6 or 7. Usually this
corresponds with crewmates being unflipped or flipped, respectively.
But warp lines' rules overlap with rules 6 and 7. If a warp line is
vertical, its rule is 5, and if it is horizontal, its rule is 7.
Now, usually, this wouldn't be an issue, but getcrewman() does a color
check as well. And for cyan, that is color 0. However, if an entity
doesn't use a color, it just defaults to color 0. So, getcrewman() found
an entity with a rule of 7 and a color of 0. This must mean it's a cyan
crewmate! But, well, it's actually just a horizontal warp line.
This commit prevents the above from happening.
2020-01-16 05:55:53 +01:00
|
|
|
if ((entities[i].type == 12 || entities[i].type == 14)
|
|
|
|
&& (entities[i].rule == 6 || entities[i].rule == 7))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if(entities[i].colour==t)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int entityclass::getcustomcrewman( int t )
|
|
|
|
{
|
|
|
|
//Returns the index of the crewman with colour index given by t
|
|
|
|
if (t == 0) t = 0;
|
|
|
|
if (t == 1) t = 20;
|
|
|
|
if (t == 2) t = 14;
|
|
|
|
if (t == 3) t = 15;
|
|
|
|
if (t == 4) t = 13;
|
|
|
|
if (t == 5) t = 16;
|
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
for (size_t i = 0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (entities[i].type == 55)
|
|
|
|
{
|
|
|
|
if(entities[i].colour==t)
|
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int entityclass::getteleporter()
|
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
for (size_t i = 0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:50:16 +02:00
|
|
|
if(entities[i].type==100)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::rectset( int xi, int yi, int wi, int hi )
|
|
|
|
{
|
|
|
|
temprect.x = xi;
|
|
|
|
temprect.y = yi;
|
|
|
|
temprect.w = wi;
|
|
|
|
temprect.h = hi;
|
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::rect2set( int xi, int yi, int wi, int hi )
|
|
|
|
{
|
|
|
|
temprect2.x = xi;
|
|
|
|
temprect2.y = yi;
|
|
|
|
temprect2.w = wi;
|
|
|
|
temprect2.h = hi;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool entityclass::entitycollide( int a, int b )
|
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (a < 0 || a > (int) entities.size() || b < 0 || b > (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("entitycollide() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
//Do entities a and b collide?
|
|
|
|
tempx = entities[a].xp + entities[a].cx;
|
|
|
|
tempy = entities[a].yp + entities[a].cy;
|
|
|
|
tempw = entities[a].w;
|
|
|
|
temph = entities[a].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
|
|
|
|
tempx = entities[b].xp + entities[b].cx;
|
|
|
|
tempy = entities[b].yp + entities[b].cy;
|
|
|
|
tempw = entities[b].w;
|
|
|
|
temph = entities[b].h;
|
|
|
|
rect2set(tempx, tempy, tempw, temph);
|
|
|
|
|
2020-04-02 21:30:37 +02:00
|
|
|
if (help.intersects(temprect, temprect2)) return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool entityclass::checkdamage()
|
|
|
|
{
|
|
|
|
//Returns true if player entity (rule 0) collides with a damagepoint
|
2020-04-03 22:50:16 +02:00
|
|
|
for(size_t i=0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if(entities[i].rule==0)
|
|
|
|
{
|
|
|
|
tempx = entities[i].xp + entities[i].cx;
|
|
|
|
tempy = entities[i].yp + entities[i].cy;
|
|
|
|
tempw = entities[i].w;
|
|
|
|
temph = entities[i].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
|
2020-04-04 01:11:02 +02:00
|
|
|
for (size_t j=0; j<blocks.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
if (blocks[j].type == DAMAGE && help.intersects(blocks[j].rect, temprect))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool entityclass::scmcheckdamage()
|
|
|
|
{
|
|
|
|
//Returns true if supercrewmate collides with a damagepoint
|
2020-04-03 22:50:16 +02:00
|
|
|
for(size_t i=0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if(entities[i].type==14)
|
|
|
|
{
|
|
|
|
tempx = entities[i].xp + entities[i].cx;
|
|
|
|
tempy = entities[i].yp + entities[i].cy;
|
|
|
|
tempw = entities[i].w;
|
|
|
|
temph = entities[i].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
|
2020-04-04 01:11:02 +02:00
|
|
|
for (size_t j=0; j<blocks.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
if (blocks[j].type == DAMAGE && help.intersects(blocks[j].rect, temprect))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::settemprect( int t )
|
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
//setup entity t in temprect
|
|
|
|
tempx = entities[t].xp + entities[t].cx;
|
|
|
|
tempy = entities[t].yp + entities[t].cy;
|
|
|
|
tempw = entities[t].w;
|
|
|
|
temph = entities[t].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
}
|
|
|
|
|
|
|
|
int entityclass::checktrigger()
|
|
|
|
{
|
|
|
|
//Returns an int player entity (rule 0) collides with a trigger
|
2020-04-03 22:50:16 +02:00
|
|
|
for(size_t i=0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if(entities[i].rule==0)
|
|
|
|
{
|
|
|
|
tempx = entities[i].xp + entities[i].cx;
|
|
|
|
tempy = entities[i].yp + entities[i].cy;
|
|
|
|
tempw = entities[i].w;
|
|
|
|
temph = entities[i].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
|
2020-04-04 01:11:02 +02:00
|
|
|
for (size_t j=0; j<blocks.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
if (blocks[j].type == TRIGGER && help.intersects(blocks[j].rect, temprect))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
activetrigger = blocks[j].trigger;
|
|
|
|
return blocks[j].trigger;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int entityclass::checkactivity()
|
|
|
|
{
|
|
|
|
//Returns an int player entity (rule 0) collides with an activity
|
2020-04-03 22:50:16 +02:00
|
|
|
for(size_t i=0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if(entities[i].rule==0)
|
|
|
|
{
|
|
|
|
tempx = entities[i].xp + entities[i].cx;
|
|
|
|
tempy = entities[i].yp + entities[i].cy;
|
|
|
|
tempw = entities[i].w;
|
|
|
|
temph = entities[i].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
|
2020-04-04 01:11:02 +02:00
|
|
|
for (size_t j=0; j<blocks.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
if (blocks[j].type == ACTIVITY && help.intersects(blocks[j].rect, temprect))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
return j;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int entityclass::getgridpoint( int t )
|
|
|
|
{
|
|
|
|
t = (t - (t % 8)) / 8;
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool entityclass::checkplatform()
|
|
|
|
{
|
|
|
|
//Return true if rectset intersects a moving platform, setups px & py to the platform x & y
|
2020-04-04 01:11:02 +02:00
|
|
|
for (size_t i = 0; i < blocks.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
if (blocks[i].type == BLOCK && help.intersects(blocks[i].rect, temprect))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
px = blocks[i].xp;
|
|
|
|
py = blocks[i].yp;
|
|
|
|
return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool entityclass::checkblocks()
|
|
|
|
{
|
2020-04-04 01:11:02 +02:00
|
|
|
for (size_t i = 0; i < blocks.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
if(!skipdirblocks && blocks[i].type == DIRECTIONAL)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-04 02:06:07 +02:00
|
|
|
if (dy > 0 && blocks[i].trigger == 0) if (help.intersects(blocks[i].rect, temprect)) return true;
|
|
|
|
if (dy <= 0 && blocks[i].trigger == 1) if (help.intersects(blocks[i].rect, temprect)) return true;
|
|
|
|
if (dx > 0 && blocks[i].trigger == 2) if (help.intersects(blocks[i].rect, temprect)) return true;
|
|
|
|
if (dx <= 0 && blocks[i].trigger == 3) if (help.intersects(blocks[i].rect, temprect)) return true;
|
|
|
|
}
|
|
|
|
if (blocks[i].type == BLOCK && help.intersects(blocks[i].rect, temprect))
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (blocks[i].type == SAFE && (dr)==1 && help.intersects(blocks[i].rect, temprect))
|
|
|
|
{
|
|
|
|
return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
bool entityclass::checkwall()
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//Returns true if entity setup in temprect collides with a wall
|
|
|
|
//used for proper collision functions; you can't just, like, call it
|
|
|
|
//whenever you feel like it and expect a response
|
|
|
|
//
|
|
|
|
//that won't work at all
|
|
|
|
if(skipblocks)
|
|
|
|
{
|
|
|
|
if (checkblocks()) return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
tempx = getgridpoint(temprect.x);
|
|
|
|
tempy = getgridpoint(temprect.y);
|
|
|
|
tempw = getgridpoint(temprect.x + temprect.w - 1);
|
|
|
|
temph = getgridpoint(temprect.y + temprect.h - 1);
|
|
|
|
if (map.collide(tempx, tempy)) return true;
|
|
|
|
if (map.collide(tempw, tempy)) return true;
|
|
|
|
if (map.collide(tempx, temph)) return true;
|
|
|
|
if (map.collide(tempw, temph)) return true;
|
|
|
|
if (temprect.h >= 12)
|
|
|
|
{
|
|
|
|
tpy1 = getgridpoint(temprect.y + 6);
|
|
|
|
if (map.collide(tempx, tpy1)) return true;
|
|
|
|
if (map.collide(tempw, tpy1)) return true;
|
|
|
|
if (temprect.h >= 18)
|
|
|
|
{
|
|
|
|
tpy1 = getgridpoint(temprect.y + 12);
|
|
|
|
if (map.collide(tempx, tpy1)) return true;
|
|
|
|
if (map.collide(tempw, tpy1)) return true;
|
|
|
|
if (temprect.h >= 24)
|
|
|
|
{
|
|
|
|
tpy1 = getgridpoint(temprect.y + 18);
|
|
|
|
if (map.collide(tempx, tpy1)) return true;
|
|
|
|
if (map.collide(tempw, tpy1)) return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (temprect.w >= 12)
|
|
|
|
{
|
|
|
|
tpx1 = getgridpoint(temprect.x + 6);
|
|
|
|
if (map.collide(tpx1, tempy)) return true;
|
|
|
|
if (map.collide(tpx1, temph)) return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
float entityclass::hplatformat()
|
|
|
|
{
|
|
|
|
//Returns first entity of horizontal platform at (px, py), -1000 otherwise.
|
2020-04-03 22:50:16 +02:00
|
|
|
for (size_t i = 0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 23:48:27 +02:00
|
|
|
if (entities[i].rule == 2 && entities[i].behave >= 2
|
|
|
|
&& entities[i].xp == px && entities[i].yp == py)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 23:48:27 +02:00
|
|
|
if (entities[i].behave == 8) //threadmill!
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 23:48:27 +02:00
|
|
|
return entities[i].para;
|
|
|
|
}
|
|
|
|
else if(entities[i].behave == 9) //threadmill!
|
|
|
|
{
|
|
|
|
return -entities[i].para;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return entities[i].vx;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1000;
|
|
|
|
}
|
|
|
|
|
|
|
|
int entityclass::yline( int a, int b )
|
|
|
|
{
|
|
|
|
if (a < b) return -1;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool entityclass::entityhlinecollide( int t, int l )
|
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size() || l < 0 || l >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("entityhlinecollide() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
//Returns true is entity t collided with the horizontal line l.
|
|
|
|
if(entities[t].xp + entities[t].cx+entities[t].w>=entities[l].xp)
|
|
|
|
{
|
|
|
|
if(entities[t].xp + entities[t].cx<=entities[l].xp+entities[l].w)
|
|
|
|
{
|
|
|
|
linetemp = 0;
|
|
|
|
|
|
|
|
linetemp += yline(entities[t].yp, entities[l].yp);
|
|
|
|
linetemp += yline(entities[t].yp + entities[t].h, entities[l].yp);
|
|
|
|
linetemp += yline(entities[t].oldyp, entities[l].yp);
|
|
|
|
linetemp += yline(entities[t].oldyp + entities[t].h, entities[l].yp);
|
|
|
|
|
|
|
|
if (linetemp > -4 && linetemp < 4) return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool entityclass::entityvlinecollide( int t, int l )
|
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size() || l < 0 || l >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("entityvlinecollide() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
//Returns true is entity t collided with the vertical line l.
|
2020-04-03 23:48:27 +02:00
|
|
|
if(entities[t].yp + entities[t].cy+entities[t].h>=entities[l].yp
|
|
|
|
&& entities[t].yp + entities[t].cy<=entities[l].yp+entities[l].h)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 23:48:27 +02:00
|
|
|
linetemp = 0;
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 23:48:27 +02:00
|
|
|
linetemp += yline(entities[t].xp + entities[t].cx+1, entities[l].xp);
|
|
|
|
linetemp += yline(entities[t].xp + entities[t].cx+1 + entities[t].w, entities[l].xp);
|
|
|
|
linetemp += yline(entities[t].oldxp + entities[t].cx+1, entities[l].xp);
|
|
|
|
linetemp += yline(entities[t].oldxp + entities[t].cx+1 + entities[t].w, entities[l].xp);
|
2020-01-01 21:29:24 +01:00
|
|
|
|
2020-04-03 23:48:27 +02:00
|
|
|
if (linetemp > -4 && linetemp < 4) return true;
|
|
|
|
return false;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool entityclass::entitywarphlinecollide(int t, int l) {
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size() || l < 0 || l >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("entitywarphlinecollide() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-04-02 22:42:50 +02:00
|
|
|
//Returns true is entity t collided with the horizontal line l.
|
2020-04-03 23:48:27 +02:00
|
|
|
if(entities[t].xp + entities[t].cx+entities[t].w>=entities[l].xp
|
|
|
|
&&entities[t].xp + entities[t].cx<=entities[l].xp+entities[l].w){
|
|
|
|
linetemp = 0;
|
|
|
|
if (entities[l].yp < 120) {
|
|
|
|
//Top line
|
|
|
|
if (entities[t].vy < 0) {
|
|
|
|
if (entities[t].yp < entities[l].yp + 10) linetemp++;
|
|
|
|
if (entities[t].yp + entities[t].h < entities[l].yp + 10) linetemp++;
|
|
|
|
if (entities[t].oldyp < entities[l].yp + 10) linetemp++;
|
|
|
|
if (entities[t].oldyp + entities[t].h < entities[l].yp + 10) linetemp++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (linetemp > 0) return true;
|
|
|
|
return false;
|
|
|
|
}else {
|
|
|
|
//Bottom line
|
|
|
|
if (entities[t].vy > 0) {
|
|
|
|
if (entities[t].yp > entities[l].yp - 10) linetemp++;
|
|
|
|
if (entities[t].yp + entities[t].h > entities[l].yp - 10) linetemp++;
|
|
|
|
if (entities[t].oldyp > entities[l].yp - 10) linetemp++;
|
|
|
|
if (entities[t].oldyp + entities[t].h > entities[l].yp - 10) linetemp++;
|
2020-04-02 22:42:50 +02:00
|
|
|
}
|
2020-04-03 23:48:27 +02:00
|
|
|
|
|
|
|
if (linetemp > 0) return true;
|
|
|
|
return false;
|
2020-04-02 22:42:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-02 21:41:33 +02:00
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
bool entityclass::entitywarpvlinecollide(int t, int l) {
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size() || l < 0 || l >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("entitywarpvlinecollide() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-04-02 22:42:50 +02:00
|
|
|
//Returns true is entity t collided with the vertical warp line l.
|
2020-04-03 23:48:27 +02:00
|
|
|
if(entities[t].yp + entities[t].cy+entities[t].h>=entities[l].yp
|
|
|
|
&& entities[t].yp + entities[t].cy <= entities[l].yp + entities[l].h) {
|
|
|
|
linetemp = 0;
|
|
|
|
if (entities[l].xp < 160) {
|
|
|
|
//Left hand line
|
|
|
|
if (entities[t].xp + entities[t].cx + 1 < entities[l].xp + 10) linetemp++;
|
|
|
|
if (entities[t].xp + entities[t].cx+1 + entities[t].w < entities[l].xp + 10) linetemp++;
|
|
|
|
if (entities[t].oldxp + entities[t].cx + 1 < entities[l].xp + 10) linetemp++;
|
|
|
|
if (entities[t].oldxp + entities[t].cx + 1 + entities[t].w < entities[l].xp + 10) linetemp++;
|
|
|
|
|
|
|
|
if (linetemp > 0) return true;
|
|
|
|
return false;
|
|
|
|
}else {
|
|
|
|
//Right hand line
|
|
|
|
if (entities[t].xp + entities[t].cx + 1 > entities[l].xp - 10) linetemp++;
|
|
|
|
if (entities[t].xp + entities[t].cx+1 + entities[t].w > entities[l].xp - 10) linetemp++;
|
|
|
|
if (entities[t].oldxp + entities[t].cx + 1 > entities[l].xp - 10) linetemp++;
|
|
|
|
if (entities[t].oldxp + entities[t].cx + 1 + entities[t].w > entities[l].xp - 10) linetemp++;
|
|
|
|
|
|
|
|
if (linetemp > 0) return true;
|
|
|
|
return false;
|
2020-04-02 22:42:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
float entityclass::entitycollideplatformroof( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("entitycollideplatformroof() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return -1000;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
tempx = entities[t].xp + entities[t].cx;
|
|
|
|
tempy = entities[t].yp + entities[t].cy -1;
|
|
|
|
tempw = entities[t].w;
|
|
|
|
temph = entities[t].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
|
|
|
|
if (checkplatform())
|
|
|
|
{
|
|
|
|
//px and py now contain an x y coordinate for a platform, find it
|
|
|
|
return hplatformat();
|
|
|
|
}
|
|
|
|
return -1000;
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
float entityclass::entitycollideplatformfloor( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("entitycollideplatformfloor() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return -1000;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
tempx = entities[t].xp + entities[t].cx;
|
|
|
|
tempy = entities[t].yp + entities[t].cy + 1;
|
|
|
|
tempw = entities[t].w;
|
|
|
|
temph = entities[t].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
|
|
|
|
if (checkplatform())
|
|
|
|
{
|
|
|
|
//px and py now contain an x y coordinate for a platform, find it
|
|
|
|
return hplatformat();
|
|
|
|
}
|
|
|
|
return -1000;
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
bool entityclass::entitycollidefloor( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("entitycollidefloor() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
//see? like here, for example!
|
|
|
|
tempx = entities[t].xp + entities[t].cx;
|
|
|
|
tempy = entities[t].yp + entities[t].cy + 1;
|
|
|
|
tempw = entities[t].w;
|
|
|
|
temph = entities[t].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
if (checkwall()) return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
bool entityclass::entitycollideroof( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("entitycollideroof() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
//and here!
|
|
|
|
tempx = entities[t].xp + entities[t].cx;
|
|
|
|
tempy = entities[t].yp + entities[t].cy - 1;
|
|
|
|
tempw = entities[t].w;
|
|
|
|
temph = entities[t].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
if (checkwall()) return true;
|
2020-01-01 21:29:24 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
bool entityclass::testwallsx( int t, int tx, int ty )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("testwallsx() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
tempx = tx + entities[t].cx;
|
|
|
|
tempy = ty + entities[t].cy;
|
|
|
|
tempw = entities[t].w;
|
|
|
|
temph = entities[t].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
|
|
|
|
if (entities[t].rule < 2)
|
|
|
|
{
|
|
|
|
skipblocks = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
skipblocks = false;
|
|
|
|
}
|
|
|
|
if (entities[t].type == 14) skipblocks = true;
|
|
|
|
dx = 0;
|
|
|
|
dy = 0;
|
|
|
|
if (entities[t].rule == 0) dx = entities[t].vx;
|
|
|
|
dr = entities[t].rule;
|
|
|
|
|
|
|
|
//Ok, now we check walls
|
2020-03-31 02:46:36 +02:00
|
|
|
if (checkwall())
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (entities[t].vx > 1.0f)
|
|
|
|
{
|
|
|
|
entities[t].vx--;
|
|
|
|
entities[t].newxp = entities[t].xp + entities[t].vx;
|
2020-03-31 02:46:36 +02:00
|
|
|
return testwallsx(t, entities[t].newxp, entities[t].yp);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else if (entities[t].vx < -1.0f)
|
|
|
|
{
|
|
|
|
entities[t].vx++;
|
|
|
|
entities[t].newxp = entities[t].xp + entities[t].vx;
|
2020-03-31 02:46:36 +02:00
|
|
|
return testwallsx(t, entities[t].newxp, entities[t].yp);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[t].vx=0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
bool entityclass::testwallsy( int t, float tx, float ty )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("testwallsy() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
tempx = static_cast<int>(tx) + entities[t].cx;
|
|
|
|
tempy = static_cast<int>(ty) + entities[t].cy;
|
|
|
|
tempw = entities[t].w;
|
|
|
|
temph = entities[t].h;
|
|
|
|
rectset(tempx, tempy, tempw, temph);
|
|
|
|
|
|
|
|
if (entities[t].rule < 2)
|
|
|
|
{
|
|
|
|
skipblocks = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
skipblocks = false;
|
|
|
|
}
|
|
|
|
if (entities[t].type == 14) skipblocks = true;
|
|
|
|
|
|
|
|
dx = 0;
|
|
|
|
dy = 0;
|
|
|
|
if (entities[t].rule == 0) dy = entities[t].vy;
|
|
|
|
dr = entities[t].rule;
|
|
|
|
|
|
|
|
//Ok, now we check walls
|
2020-03-31 02:46:36 +02:00
|
|
|
if (checkwall())
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (entities[t].vy > 1)
|
|
|
|
{
|
|
|
|
entities[t].vy--;
|
|
|
|
entities[t].newyp = int(entities[t].yp + entities[t].vy);
|
2020-03-31 02:46:36 +02:00
|
|
|
return testwallsy(t, entities[t].xp, entities[t].newyp);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else if (entities[t].vy < -1)
|
|
|
|
{
|
|
|
|
entities[t].vy++;
|
|
|
|
entities[t].newyp = int(entities[t].yp + entities[t].vy);
|
2020-03-31 02:46:36 +02:00
|
|
|
return testwallsy(t, entities[t].xp, entities[t].newyp);
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[t].vy=0;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::fixfriction( int t, float xfix, float xrate, float yrate )
|
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("fixfriction() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
if (entities[t].vx > xfix) entities[t].vx -= xrate;
|
|
|
|
if (entities[t].vx < xfix) entities[t].vx += xrate;
|
|
|
|
if (entities[t].vy > 0) entities[t].vy -= yrate;
|
|
|
|
if (entities[t].vy < 0) entities[t].vy += yrate;
|
|
|
|
if (entities[t].vy > 10) entities[t].vy = 10;
|
|
|
|
if (entities[t].vy < -10) entities[t].vy = -10;
|
|
|
|
if (entities[t].vx > 6) entities[t].vx = 6.0f;
|
|
|
|
if (entities[t].vx < -6) entities[t].vx = -6.0f;
|
|
|
|
|
|
|
|
if (std::abs(entities[t].vx-xfix) <= xrate) entities[t].vx = xfix;
|
|
|
|
if (std::abs(entities[t].vy) < yrate) entities[t].vy = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::applyfriction( int t, float xrate, float yrate )
|
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("applyfriction() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
if (entities[t].vx > 0.00f) entities[t].vx -= xrate;
|
|
|
|
if (entities[t].vx < 0.00f) entities[t].vx += xrate;
|
|
|
|
if (entities[t].vy > 0.00f) entities[t].vy -= yrate;
|
|
|
|
if (entities[t].vy < 0.00f) entities[t].vy += yrate;
|
|
|
|
if (entities[t].vy > 10.00f) entities[t].vy = 10.0f;
|
|
|
|
if (entities[t].vy < -10.00f) entities[t].vy = -10.0f;
|
|
|
|
if (entities[t].vx > 6.00f) entities[t].vx = 6.0f;
|
|
|
|
if (entities[t].vx < -6.00f) entities[t].vx = -6.0f;
|
|
|
|
|
|
|
|
if (std::abs(entities[t].vx) < xrate) entities[t].vx = 0.0f;
|
|
|
|
if (std::abs(entities[t].vy) < yrate) entities[t].vy = 0.0f;
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
void entityclass::updateentitylogic( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 22:55:12 +02:00
|
|
|
puts("updateentitylogic() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
entities[t].vx = entities[t].vx + entities[t].ax;
|
|
|
|
entities[t].vy = entities[t].vy + entities[t].ay;
|
|
|
|
entities[t].ax = 0;
|
|
|
|
|
|
|
|
if (entities[t].gravity)
|
|
|
|
{
|
|
|
|
if (entities[t].rule == 0)
|
|
|
|
{
|
|
|
|
if(game.gravitycontrol==0)
|
|
|
|
{
|
|
|
|
entities[t].ay = 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[t].ay = -3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (entities[t].rule == 7)
|
|
|
|
{
|
|
|
|
entities[t].ay = -3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[t].ay = 3;
|
|
|
|
}
|
|
|
|
applyfriction(t, game.inertia, 0.25f);
|
|
|
|
}
|
|
|
|
|
|
|
|
entities[t].newxp = entities[t].xp + entities[t].vx;
|
|
|
|
entities[t].newyp = entities[t].yp + entities[t].vy;
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
void entityclass::entitymapcollision( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 22:55:12 +02:00
|
|
|
puts("entitymapcollision() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
if (testwallsx(t, entities[t].newxp, entities[t].yp))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
entities[t].xp = entities[t].newxp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (entities[t].onwall > 0) entities[t].state = entities[t].onwall;
|
|
|
|
if (entities[t].onxwall > 0) entities[t].state = entities[t].onxwall;
|
|
|
|
}
|
2020-03-31 02:46:36 +02:00
|
|
|
if (testwallsy(t, entities[t].xp, entities[t].newyp))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
entities[t].yp = entities[t].newyp;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (entities[t].onwall > 0) entities[t].state = entities[t].onwall;
|
|
|
|
if (entities[t].onywall > 0) entities[t].state = entities[t].onywall;
|
|
|
|
entities[t].jumpframe = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
void entityclass::movingplatformfix( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("movingplatformfix() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
//If this intersects the player, then we move the player along it
|
|
|
|
int j = getplayer();
|
2020-06-13 05:36:08 +02:00
|
|
|
if (j > -1 && entitycollide(t, j))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//ok, bollox, let's make sure
|
|
|
|
entities[j].yp = entities[j].yp + int(entities[j].vy);
|
|
|
|
if (entitycollide(t, j))
|
|
|
|
{
|
|
|
|
entities[j].yp = entities[j].yp - int(entities[j].vy);
|
|
|
|
entities[j].vy = entities[t].vy;
|
|
|
|
entities[j].newyp = entities[j].yp + int(entities[j].vy);
|
2020-03-31 02:46:36 +02:00
|
|
|
if (testwallsy(j, entities[j].xp, entities[j].newyp))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (entities[t].vy > 0)
|
|
|
|
{
|
|
|
|
entities[j].yp = entities[t].yp + entities[t].h;
|
|
|
|
entities[j].vy = 0;
|
|
|
|
entities[j].onroof = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[j].yp = entities[t].yp - entities[j].h-entities[j].cy;
|
|
|
|
entities[j].vy = 0;
|
|
|
|
entities[j].onground = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[t].state = entities[t].onwall;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
void entityclass::scmmovingplatformfix( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("scmmovingplatformfix() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
//If this intersects the SuperCrewMate, then we move them along it
|
|
|
|
int j = getscm();
|
|
|
|
if (entitycollide(t, j))
|
|
|
|
{
|
|
|
|
//ok, bollox, let's make sure
|
|
|
|
entities[j].yp = entities[j].yp + (entities[j].vy);
|
|
|
|
if (entitycollide(t, j))
|
|
|
|
{
|
|
|
|
entities[j].yp = entities[j].yp - (entities[j].vy);
|
|
|
|
entities[j].vy = entities[t].vy;
|
|
|
|
entities[j].newyp = static_cast<float>(entities[j].yp) + entities[j].vy;
|
2020-03-31 02:46:36 +02:00
|
|
|
if (testwallsy(j, entities[j].xp, entities[j].newyp))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
if (entities[t].vy > 0)
|
|
|
|
{
|
|
|
|
entities[j].yp = entities[t].yp + entities[t].h;
|
|
|
|
entities[j].vy = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[j].yp = entities[t].yp - entities[j].h-entities[j].cy;
|
|
|
|
entities[j].vy = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[t].state = entities[t].onwall;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
void entityclass::hormovingplatformfix( int t )
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-05-05 01:41:30 +02:00
|
|
|
if (t < 0 || t >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("hormovingplatformfix() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-01 21:29:24 +01:00
|
|
|
//If this intersects the player, then we move the player along it
|
|
|
|
//for horizontal platforms, this is simplier
|
|
|
|
createblock(0, entities[t].xp, entities[t].yp, entities[t].w, entities[t].h);
|
|
|
|
}
|
|
|
|
|
|
|
|
void entityclass::customwarplinecheck(int i) {
|
2020-05-05 01:41:30 +02:00
|
|
|
if (i < 0 || i >= (int) entities.size())
|
|
|
|
{
|
2020-05-05 19:37:52 +02:00
|
|
|
puts("customwarplinecheck() out-of-bounds!");
|
2020-05-05 01:41:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-04-02 22:42:50 +02:00
|
|
|
//Turns on obj.customwarpmodevon and obj.customwarpmodehon if player collides
|
|
|
|
//with warp lines
|
|
|
|
|
2020-04-03 22:57:02 +02:00
|
|
|
//We test entity to entity
|
|
|
|
for (int j = 0; j < (int) entities.size(); j++) {
|
2020-04-03 23:50:08 +02:00
|
|
|
if (i != j) {
|
2020-04-03 23:48:27 +02:00
|
|
|
if (entities[i].rule == 0 && entities[j].rule == 5 //Player vs vertical line!
|
|
|
|
&& (entities[j].type == 51 || entities[j].type == 52)
|
|
|
|
&& entitywarpvlinecollide(i, j)) {
|
|
|
|
customwarpmodevon = true;
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
2020-04-02 22:42:50 +02:00
|
|
|
|
2020-04-03 23:48:27 +02:00
|
|
|
if (entities[i].rule == 0 && entities[j].rule == 7 //Player vs horizontal WARP line
|
|
|
|
&& (entities[j].type == 53 || entities[j].type == 54)
|
|
|
|
&& entitywarphlinecollide(i, j)) {
|
|
|
|
customwarpmodehon = true;
|
2020-04-02 22:42:50 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
|
2020-03-31 02:46:36 +02:00
|
|
|
void entityclass::entitycollisioncheck()
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-06-14 03:13:04 +02:00
|
|
|
std::vector<SDL_Surface*>& spritesvec = graphics.flipmode ? graphics.flipsprites : graphics.sprites;
|
|
|
|
|
2020-04-03 22:50:16 +02:00
|
|
|
for (size_t i = 0; i < entities.size(); i++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//We test entity to entity
|
|
|
|
for (size_t j = 0; j < entities.size(); j++)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 23:50:08 +02:00
|
|
|
if (i!=j)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[i].rule == 0 && entities[j].rule == 1 && entities[j].harmful)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//player i hits enemy or enemy bullet j
|
|
|
|
if (entitycollide(i, j) && !map.invincibility)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[i].size == 0 && (entities[j].size == 0 || entities[j].size == 12))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//They're both sprites, so do a per pixel collision
|
|
|
|
colpoint1.x = entities[i].xp;
|
|
|
|
colpoint1.y = entities[i].yp;
|
|
|
|
colpoint2.x = entities[j].xp;
|
|
|
|
colpoint2.y = entities[j].yp;
|
2020-06-14 03:35:12 +02:00
|
|
|
int drawframe1 = entities[i].drawframe;
|
|
|
|
int drawframe2 = entities[j].drawframe;
|
|
|
|
if (INBOUNDS(drawframe1, spritesvec) && INBOUNDS(drawframe2, spritesvec)
|
|
|
|
&& graphics.Hitest(spritesvec[drawframe1],
|
|
|
|
colpoint1, spritesvec[drawframe2], colpoint2))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-06-14 03:13:04 +02:00
|
|
|
//Do the collision stuff
|
|
|
|
game.deathseq = 30;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//Ok, then we just assume a normal bounding box collision
|
|
|
|
game.deathseq = 30;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
if (entities[i].rule == 0 && entities[j].rule == 2) //Moving platforms
|
|
|
|
{
|
|
|
|
if (entitycollide(i, j)) removeblockat(entities[j].xp, entities[j].yp);
|
|
|
|
}
|
|
|
|
if (entities[i].rule == 0 && entities[j].rule == 3) //Entity to entity
|
|
|
|
{
|
|
|
|
if(entities[j].onentity>0)
|
|
|
|
{
|
|
|
|
if (entitycollide(i, j)) entities[j].state = entities[j].onentity;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (entities[i].rule == 0 && entities[j].rule == 4) //Player vs horizontal line!
|
|
|
|
{
|
|
|
|
if(game.deathseq==-1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//Here we compare the player's old position versus his new one versus the line.
|
|
|
|
//All points either be above or below it. Otherwise, there was a collision this frame.
|
|
|
|
if (entities[j].onentity > 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entityhlinecollide(i, j))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
music.playef(8);
|
|
|
|
game.gravitycontrol = (game.gravitycontrol + 1) % 2;
|
|
|
|
game.totalflips++;
|
|
|
|
if (game.gravitycontrol == 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[i].vy < 1) entities[i].vy = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (entities[i].vy > -1) entities[i].vy = -1;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
|
|
|
|
entities[j].state = entities[j].onentity;
|
|
|
|
entities[j].life = 6;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
if (entities[i].rule == 0 && entities[j].rule == 5) //Player vs vertical line!
|
|
|
|
{
|
|
|
|
if(game.deathseq==-1)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if(entities[j].onentity>0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entityvlinecollide(i, j))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
entities[j].state = entities[j].onentity;
|
|
|
|
entities[j].life = 4;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
if (entities[i].rule == 0 && entities[j].rule == 6) //Player versus crumbly blocks! Special case
|
|
|
|
{
|
|
|
|
if (entities[j].onentity > 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//ok; only check the actual collision if they're in a close proximity
|
|
|
|
temp = entities[i].yp - entities[j].yp;
|
2020-05-13 10:15:34 +02:00
|
|
|
if (temp > -30 && temp < 30)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
temp = entities[i].xp - entities[j].xp;
|
2020-05-13 10:15:34 +02:00
|
|
|
if (temp > -30 && temp < 30)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entitycollide(i, j)) entities[j].state = entities[j].onentity;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
}
|
|
|
|
if (game.supercrewmate)
|
|
|
|
{
|
|
|
|
//some extra collisions
|
|
|
|
if (entities[i].type == 14) //i is the supercrewmate
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[j].rule == 1 && entities[j].harmful) //j is a harmful enemy
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//player i hits enemy or enemy bullet j
|
|
|
|
if (entitycollide(i, j) && !map.invincibility)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[i].size == 0 && entities[j].size == 0)
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//They're both sprites, so do a per pixel collision
|
|
|
|
colpoint1.x = entities[i].xp;
|
|
|
|
colpoint1.y = entities[i].yp;
|
|
|
|
colpoint2.x = entities[j].xp;
|
|
|
|
colpoint2.y = entities[j].yp;
|
2020-06-14 03:35:12 +02:00
|
|
|
int drawframe1 = entities[i].drawframe;
|
|
|
|
int drawframe2 = entities[j].drawframe;
|
|
|
|
if (INBOUNDS(drawframe1, spritesvec) && INBOUNDS(drawframe2, spritesvec)
|
|
|
|
&& graphics.Hitest(spritesvec[drawframe1],
|
|
|
|
colpoint1, spritesvec[drawframe2], colpoint2))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-06-14 03:13:04 +02:00
|
|
|
//Do the collision stuff
|
|
|
|
game.deathseq = 30;
|
|
|
|
game.scmhurt = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
else
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
2020-04-03 22:57:02 +02:00
|
|
|
//Ok, then we just assume a normal bounding box collision
|
|
|
|
game.deathseq = 30;
|
|
|
|
game.scmhurt = true;
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-04-03 22:57:02 +02:00
|
|
|
if (entities[j].rule == 2) //Moving platforms
|
|
|
|
{
|
|
|
|
if (entitycollide(i, j)) removeblockat(entities[j].xp, entities[j].yp);
|
|
|
|
}
|
|
|
|
if (entities[j].type == 8 && entities[j].rule == 3) //Entity to entity (well, checkpoints anyway!)
|
|
|
|
{
|
|
|
|
if(entities[j].onentity>0)
|
|
|
|
{
|
|
|
|
if (entitycollide(i, j)) entities[j].state = entities[j].onentity;
|
|
|
|
}
|
|
|
|
}
|
2020-01-01 21:29:24 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//can't have the player being stuck...
|
|
|
|
int j = getplayer();
|
|
|
|
skipdirblocks = true;
|
2020-06-13 05:36:08 +02:00
|
|
|
if (j > -1 && !testwallsx(j, entities[j].xp, entities[j].yp))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//Let's try to get out...
|
|
|
|
if (entities[j].rule == 0)
|
|
|
|
{
|
|
|
|
if(game.gravitycontrol==0)
|
|
|
|
{
|
|
|
|
entities[j].yp -= 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[j].yp += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skipdirblocks = false;
|
|
|
|
|
|
|
|
//Can't have the supercrewmate getting stuck either!
|
|
|
|
if (game.supercrewmate)
|
|
|
|
{
|
|
|
|
j = getscm();
|
|
|
|
skipdirblocks = true;
|
2020-03-31 02:46:36 +02:00
|
|
|
if (!testwallsx(j, entities[j].xp, entities[j].yp))
|
2020-01-01 21:29:24 +01:00
|
|
|
{
|
|
|
|
//Let's try to get out...
|
|
|
|
if(game.gravitycontrol==0)
|
|
|
|
{
|
|
|
|
entities[j].yp -= 3;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
entities[j].yp += 3;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
skipdirblocks = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Is the player colliding with any damageblocks?
|
|
|
|
if (checkdamage() && !map.invincibility)
|
|
|
|
{
|
|
|
|
//usual player dead stuff
|
|
|
|
game.deathseq = 30;
|
|
|
|
}
|
|
|
|
|
|
|
|
//how about the supercrewmate?
|
|
|
|
if (game.supercrewmate)
|
|
|
|
{
|
|
|
|
if (scmcheckdamage() && !map.invincibility)
|
|
|
|
{
|
|
|
|
//usual player dead stuff
|
|
|
|
game.scmhurt = true;
|
|
|
|
game.deathseq = 30;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Fix the two-frame-delay when entering a room with an "init" script
This patch is very kludge-y, but at least it fixes a semi-noticeable
visual issue in custom levels that use internal scripts to spawn
entities when loading a room.
Basically, the problem here is that when the game checks for script
boxes and sets newscript, newscript has already been processed for that
frame, and when the game does load a script, script.run() has already
been processed for that frame.
That issue can be fixed, but it turns out that due to my over-30-FPS
game loop changes, there's now ANOTHER visible frame of delay between
room load and entity creation, because the render function gets called
in between the script being loaded at the end of gamelogic() and the
script actually getting run.
So... I have to temporary move script.run() to the end of gamelogic()
(in map.twoframedelayfix()), and make sure it doesn't get run next
frame, because double-evaluations are bad. To do that, I have to
introduce the kludge variable script.dontrunnextframe, which does
exactly as it says.
And with all that work, the two-frame (now three-frame) delay is fixed.
2020-06-28 02:08:57 +02:00
|
|
|
// WARNING: If updating this code, don't forget to update Map.cpp mapclass::twoframedelayfix()
|
2020-01-01 21:29:24 +01:00
|
|
|
activetrigger = -1;
|
|
|
|
if (checktrigger() > -1)
|
|
|
|
{
|
|
|
|
game.state = activetrigger;
|
|
|
|
game.statedelay = 0;
|
|
|
|
}
|
|
|
|
}
|