mirror of
https://github.com/TerryCavanagh/VVVVVV.git
synced 2024-12-23 10:09:43 +01:00
3ca7b09012
This fixes a regression that desyncs my Nova TAS after re-removing the 1-frame input delay. Quick stopping is simply holding left/right but for less than 5 frames. Viridian doesn't decelerate when you let go and they immediately stop in place. (The code calls this tapping, but "quick stopping" is a better name because you can immediately counter-strafe to stop yourself from decelrating in the first place, and that works because of this same code.) So, the sequence of events in 2.2 and previous looks like this: - gameinput() - If quick stopping, set vx to 0 - gamerender() - Change drawframe depending on vx - gamelogic() - Use drawframe for collision (whyyyyyyyyyyyyyyyyyyyyyyyyyyy) And now (ignoring the intermediate period where the whole loop order was wrong), the sequence of events in 2.3 looks like this: - gamerenderfixed() - Change drawframe depending on vx - gamerender() - gameinput() - If quick stopping, set vx to 0 - gamelogic() - Use drawframe for collision (my mind has become numb to pain) So, this means that all the player movement stuff is completely the same. Except their drawframe is going to be different. Unfortunately, I had overlooked that gameinput() sets vx and that animateentities() (in gamerenderfixed()) checks vx. Although, to be fair, it's a pretty dumb decision to make collision detection be based on the actual sprites' pixels themselves, instead of a hitbox, in the first place, so you'd expect THAT to be the end of the dumb parade. Or maybe you shouldn't, I don't know. So, what's the solution? What I've done here is added duplicates of framedelay, drawframe, and walkingframe, for collision use only. They get updated in gamelogic(), after gameinput(), which is after when vx could be set to 0. I've kept the original framedelay, drawframe, and walkingframe around, to keep the same visuals as closely as possible. However, due to the removal of the input delay, whenever you quick stop, your sprite will be wrong for just 1 frame - because when you let go of the direction key, the game will set your vx to 0 and the logical drawframe will update to reflect that, but the previous frame cannot know in advance that you'll release the key on the next frame, and so the visual drawframe will assume that you keep holding the key. Whereas in 2.2 and below, when you release a direction key, the player's position will only update to reflect that on the next frame, but the current frame can immediately recognize that and update the drawframe now, instead of retconning it later. Basically the visual drawframe assumes that you keep holding the key, and if you don't, then it takes on the value of the collision drawframe anyway, so it's okay. And it's only visual, anyway - the collision drawframe of the next frame (when you release the key) will be the same as the drawframe of the frame you release the key in 2.2 and below. But I really don't care to try and fix this for if you re-enable the input delay because it's minor and it'd be more complicated.
664 lines
9.5 KiB
C++
664 lines
9.5 KiB
C++
#include "Ent.h"
|
|
|
|
#include "Game.h"
|
|
#include "Graphics.h"
|
|
|
|
entclass::entclass(void)
|
|
{
|
|
clear();
|
|
}
|
|
|
|
void entclass::clear(void)
|
|
{
|
|
invis = false;
|
|
type = 0;
|
|
size = 0;
|
|
tile = 0;
|
|
rule = 0;
|
|
state = 0;
|
|
statedelay = 0;
|
|
life = 0;
|
|
colour = 0;
|
|
para = 0;
|
|
behave = 0;
|
|
animate = 0;
|
|
|
|
xp = 0;
|
|
yp = 0;
|
|
ax = 0;
|
|
ay = 0;
|
|
vx = 0;
|
|
vy = 0;
|
|
w = 16;
|
|
h = 16;
|
|
cx = 0;
|
|
cy = 0;
|
|
newxp = 0;
|
|
newyp = 0;
|
|
oldxp = 0;
|
|
oldyp = 0;
|
|
|
|
x1 = 0;
|
|
y1 = 0;
|
|
x2 = 320;
|
|
y2 = 240;
|
|
|
|
gravity = false;
|
|
onground = 0;
|
|
onroof = 0;
|
|
collisionframedelay = 0;
|
|
collisiondrawframe = 0;
|
|
collisionwalkingframe = 0;
|
|
visualonground = 0;
|
|
visualonroof = 0;
|
|
|
|
onentity = 0;
|
|
harmful = false;
|
|
onwall = 0;
|
|
onxwall = 0;
|
|
onywall = 0;
|
|
isplatform = false;
|
|
|
|
framedelay = 0;
|
|
drawframe = 0;
|
|
walkingframe = 0;
|
|
dir = 0;
|
|
actionframe = 0;
|
|
|
|
realcol = 0;
|
|
lerpoldxp = 0;
|
|
lerpoldyp = 0;
|
|
}
|
|
|
|
bool entclass::outside(void)
|
|
{
|
|
// Returns true if any point of the entity is outside the map.
|
|
// Adjusts velocity for a clean collision.
|
|
if (xp < x1)
|
|
{
|
|
xp = x1;
|
|
return true;
|
|
}
|
|
if (yp < y1)
|
|
{
|
|
yp = y1;
|
|
return true;
|
|
}
|
|
if (xp + w > x2)
|
|
{
|
|
xp = x2 - w;
|
|
return true;
|
|
}
|
|
if (yp + h > y2)
|
|
{
|
|
yp = y2 - h;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void entclass::setenemy( int t )
|
|
{
|
|
switch(t)
|
|
{
|
|
case 0:
|
|
//lies emitter
|
|
switch ((int) para)
|
|
{
|
|
case 0:
|
|
tile = 60;
|
|
animate = 2;
|
|
colour = 6;
|
|
behave = 10;
|
|
w = 32;
|
|
h = 32;
|
|
x1 = -200;
|
|
break;
|
|
case 1:
|
|
yp += 10;
|
|
lerpoldyp += 10;
|
|
tile = 63;
|
|
animate = 100; //LIES
|
|
colour = 6;
|
|
behave = 11;
|
|
para = 9; //destroyed when outside
|
|
x1 = -200;
|
|
x2 = 400;
|
|
w = 26;
|
|
h = 10;
|
|
cx = 1;
|
|
cy = 1;
|
|
break;
|
|
case 2:
|
|
tile = 62;
|
|
animate = 100;
|
|
colour = 6;
|
|
behave = -1;
|
|
w = 32;
|
|
h = 32;
|
|
break;
|
|
}
|
|
break;
|
|
case 1:
|
|
//FACTORY emitter
|
|
switch ((int) para)
|
|
{
|
|
case 0:
|
|
tile = 72;
|
|
animate = 3;
|
|
size = 9;
|
|
colour = 6;
|
|
behave = 12;
|
|
w = 64;
|
|
h = 40;
|
|
cx = 0;
|
|
cy = 24;
|
|
break;
|
|
case 1:
|
|
xp += 4;
|
|
lerpoldxp += 4;
|
|
yp -= 4;
|
|
lerpoldyp -= 4;
|
|
tile = 76;
|
|
animate = 100; // Clouds
|
|
colour = 6;
|
|
behave = 13;
|
|
para = -6; //destroyed when outside
|
|
x2 = 400;
|
|
w = 32;
|
|
h = 12;
|
|
cx = 0;
|
|
cy = 6;
|
|
break;
|
|
case 2:
|
|
tile = 77;
|
|
animate = 100;
|
|
colour = 6;
|
|
behave = -1;
|
|
w = 32;
|
|
h = 16;
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void entclass::setenemyroom( int rx, int ry )
|
|
{
|
|
//Simple function to initilise simple enemies
|
|
rx -= 100;
|
|
ry -= 100;
|
|
switch(rn(rx, ry))
|
|
{
|
|
//Space Station 1
|
|
case rn(12, 3): //Security Drone
|
|
tile = 36;
|
|
colour = 8;
|
|
animate = 1;
|
|
break;
|
|
case rn(13, 3): //Wavelengths
|
|
tile = 32;
|
|
colour = 7;
|
|
animate = 1;
|
|
w = 32;
|
|
break;
|
|
case rn(15, 3): //Traffic
|
|
tile = 28;
|
|
colour = 6;
|
|
animate = 1;
|
|
w = 22;
|
|
h = 32;
|
|
break;
|
|
case rn(12, 5): //The Yes Men
|
|
tile = 40;
|
|
colour = 9;
|
|
animate = 1;
|
|
w = 20;
|
|
h = 20;
|
|
break;
|
|
case rn(13, 6): //Hunchbacked Guards
|
|
tile = 44;
|
|
colour = 8;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 20;
|
|
break;
|
|
case rn(13, 4): //Communication Station
|
|
harmful = false;
|
|
if (xp == 256)
|
|
{
|
|
//transmittor
|
|
tile = 104;
|
|
colour = 4;
|
|
animate = 7;
|
|
w = 16;
|
|
h = 16;
|
|
xp -= 24;
|
|
lerpoldxp -= 24;
|
|
yp -= 16;
|
|
lerpoldyp -= 16;
|
|
}
|
|
else
|
|
{
|
|
//radar dish
|
|
tile =124;
|
|
colour = 4;
|
|
animate = 6;
|
|
w = 32;
|
|
h = 32;
|
|
cx = 4;
|
|
size = 9;
|
|
xp -= 4;
|
|
lerpoldxp -= 4;
|
|
yp -= 32;
|
|
lerpoldyp -= 32;
|
|
}
|
|
|
|
break;
|
|
//The Lab
|
|
case rn(4, 0):
|
|
tile = 78;
|
|
colour = 7;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(2, 0):
|
|
tile = 88;
|
|
colour = 11;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
//Space Station 2
|
|
case rn(14, 11):
|
|
colour = 17;
|
|
break; //Lies
|
|
case rn(16, 11):
|
|
colour = 8;
|
|
break; //Lies
|
|
case rn(13, 10):
|
|
colour = 11;
|
|
break; //Factory
|
|
case rn(13, 9):
|
|
colour = 9;
|
|
break; //Factory
|
|
case rn(13, 8):
|
|
colour = 8;
|
|
break; //Factory
|
|
case rn(11, 13): //Truth
|
|
tile = 64;
|
|
colour = 7;
|
|
animate = 100;
|
|
w = 44;
|
|
h = 10;
|
|
size = 10;
|
|
break;
|
|
case rn(17, 7): //Brass sent us under the top
|
|
tile =82;
|
|
colour = 8;
|
|
animate = 5;
|
|
w = 28;
|
|
h = 32;
|
|
cx = 4;
|
|
break;
|
|
case rn(10, 7): // (deception)
|
|
tile = 92;
|
|
colour = 6;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(14, 13): // (chose poorly)
|
|
tile = 56;
|
|
colour = 6;
|
|
animate = 1;
|
|
w = 15;
|
|
h = 24;
|
|
break;
|
|
case rn(13, 12): // (backsliders)
|
|
tile = 164;
|
|
colour = 7;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(14, 8): // (wheel of fortune room)
|
|
tile = 116;
|
|
colour = 12;
|
|
animate = 1;
|
|
w = 32;
|
|
h = 32;
|
|
break;
|
|
case rn(16, 9): // (seeing dollar signs)
|
|
tile = 68;
|
|
colour = 7;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(16, 7): // (tomb of mad carew)
|
|
tile = 106;
|
|
colour = 7;
|
|
animate = 2;
|
|
w = 24;
|
|
h = 25;
|
|
break;
|
|
//Warp Zone
|
|
case rn(15, 2): // (numbers)
|
|
tile = 100;
|
|
colour = 6;
|
|
animate = 1;
|
|
w = 32;
|
|
h = 14;
|
|
yp += 1;
|
|
lerpoldyp += 1;
|
|
break;
|
|
case rn(16, 2): // (Manequins)
|
|
tile = 52;
|
|
colour = 7;
|
|
animate = 5;
|
|
w = 16;
|
|
h = 25;
|
|
yp -= 4;
|
|
lerpoldyp -= 4;
|
|
break;
|
|
case rn(18, 0): // (Obey)
|
|
tile = 51;
|
|
colour = 11;
|
|
animate = 100;
|
|
w = 30;
|
|
h = 14;
|
|
break;
|
|
case rn(19, 1): // Ascending and Descending
|
|
tile = 48;
|
|
colour = 9;
|
|
animate = 5;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(19, 2): // Shockwave Rider
|
|
tile = 176;
|
|
colour = 6;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(18, 3): // Mind the gap
|
|
tile = 168;
|
|
colour = 7;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(17, 3): // Edge Games
|
|
if (yp ==96)
|
|
{
|
|
tile = 160;
|
|
colour = 8;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
}
|
|
else
|
|
{
|
|
tile = 156;
|
|
colour = 8;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
}
|
|
break;
|
|
case rn(16, 0): // I love you
|
|
tile = 112;
|
|
colour = 8;
|
|
animate = 5;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(14, 2): // That's why I have to kill you
|
|
tile = 114;
|
|
colour = 6;
|
|
animate = 5;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(18, 2): // Thinking with Portals
|
|
//depends on direction
|
|
if (xp ==88)
|
|
{
|
|
tile = 54+12;
|
|
colour = 12;
|
|
animate = 100;
|
|
w = 60;
|
|
h = 16;
|
|
size = 10;
|
|
}
|
|
else
|
|
{
|
|
tile = 54;
|
|
colour = 12;
|
|
animate = 100;
|
|
w = 60;
|
|
h = 16;
|
|
size = 10;
|
|
}
|
|
break;
|
|
//Final level
|
|
case rn(50-100, 53-100): //The Yes Men
|
|
tile = 40;
|
|
colour = 9;
|
|
animate = 1;
|
|
w = 20;
|
|
h = 20;
|
|
break;
|
|
case rn(48-100, 51-100): //Wavelengths
|
|
tile = 32;
|
|
colour = 7;
|
|
animate = 1;
|
|
w = 32;
|
|
break;
|
|
case rn(43-100,52-100): // Ascending and Descending
|
|
tile = 48;
|
|
colour = 9;
|
|
animate = 5;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(46-100,51-100): //kids his age
|
|
tile = 88;
|
|
colour = 11;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(43-100,51-100): // Mind the gap
|
|
tile = 168;
|
|
colour = 7;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(44-100,51-100): // vertigo?
|
|
tile = 172;
|
|
colour = 7;
|
|
animate = 100;
|
|
w = 32;
|
|
h = 32;
|
|
break;
|
|
case rn(44-100,52-100): // (backsliders)
|
|
tile = 164;
|
|
colour = 7;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(43-100, 56-100): //Intermission 1
|
|
tile = 88;
|
|
colour = 21;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
case rn(45-100, 56-100): //Intermission 1
|
|
tile = 88;
|
|
colour = 21;
|
|
animate = 1;
|
|
w = 16;
|
|
h = 16;
|
|
break;
|
|
//The elephant
|
|
case rn(11, 9):
|
|
case rn(12, 9):
|
|
case rn(11, 8):
|
|
case rn(12, 8):
|
|
tile = 0;
|
|
colour = 102;
|
|
animate = 0;
|
|
w = 464;
|
|
h = 320;
|
|
size = 11;
|
|
harmful = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void entclass::settreadmillcolour( int rx, int ry )
|
|
{
|
|
rx -= 100;
|
|
ry -= 100;
|
|
rx += 50 - 12;
|
|
ry += 50 - 14; //Space Station
|
|
|
|
tile = 20; //default as blue
|
|
switch(rn(rx, ry))
|
|
{
|
|
case rn(52, 48):
|
|
tile = 791;
|
|
break; //Cyan
|
|
|
|
case rn(49, 47):
|
|
tile = 24;
|
|
break; //Yellow
|
|
case rn(56, 44):
|
|
tile = 24;
|
|
break; //Yellow
|
|
case rn(54, 49):
|
|
tile = 24;
|
|
break; //Yellow
|
|
|
|
case rn(49, 49):
|
|
tile = 36;
|
|
break; //Green
|
|
case rn(55, 44):
|
|
tile = 36;
|
|
break; //Green
|
|
case rn(54, 43):
|
|
tile = 36;
|
|
break; //Green
|
|
case rn(53, 49):
|
|
tile = 36;
|
|
break; //Green
|
|
case rn(54, 45):
|
|
tile = 711;
|
|
break; //Green (special)
|
|
case rn(51, 48):
|
|
tile = 711;
|
|
break; //Green (special)
|
|
|
|
case rn(50, 49):
|
|
tile = 28;
|
|
break; //Purple
|
|
case rn(54, 44):
|
|
tile = 28;
|
|
break; //Purple
|
|
case rn(49, 42):
|
|
tile = 28;
|
|
break; //Purple
|
|
case rn(55, 43):
|
|
tile = 28;
|
|
break; //Purple
|
|
case rn(54, 47):
|
|
tile = 28;
|
|
break; //Purple
|
|
case rn(53, 48):
|
|
tile = 28;
|
|
break; //Purple
|
|
|
|
case rn(51, 47):
|
|
tile = 32;
|
|
break; //Red
|
|
case rn(52, 49):
|
|
tile = 32;
|
|
break; //Red
|
|
case rn(48, 43):
|
|
tile = 32;
|
|
break; //Red
|
|
case rn(55, 47):
|
|
tile = 32;
|
|
break; //Red
|
|
case rn(54, 48):
|
|
tile = 32;
|
|
break; //Red
|
|
default:
|
|
return;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void entclass::updatecolour(void)
|
|
{
|
|
switch (size)
|
|
{
|
|
case 0: // Sprites
|
|
case 7: // Teleporter
|
|
case 9: // Really Big Sprite! (2x2)
|
|
case 10: // 2x1 Sprite
|
|
case 13: // Special for epilogue: huge hero!
|
|
graphics.setcol(colour);
|
|
realcol = graphics.ct.colour;
|
|
break;
|
|
case 3: // Big chunky pixels!
|
|
realcol = graphics.bigchunkygetcol(colour);
|
|
break;
|
|
case 4: // Small pickups
|
|
graphics.huetilesetcol(colour);
|
|
realcol = graphics.ct.colour;
|
|
break;
|
|
case 11: // The fucking elephant
|
|
if (game.noflashingmode)
|
|
{
|
|
graphics.setcol(22);
|
|
}
|
|
else
|
|
{
|
|
graphics.setcol(colour);
|
|
}
|
|
realcol = graphics.ct.colour;
|
|
break;
|
|
case 12: // Regular sprites that don't wrap
|
|
// if we're outside the screen, we need to draw indicators
|
|
if ((xp < -20 && vx > 0) || (xp > 340 && vx < 0))
|
|
{
|
|
graphics.setcol(23);
|
|
}
|
|
else
|
|
{
|
|
graphics.setcol(colour);
|
|
}
|
|
realcol = graphics.ct.colour;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool entclass::ishumanoid(void)
|
|
{
|
|
return type == 0
|
|
|| type == 12
|
|
|| type == 14
|
|
|| type == 55;
|
|
}
|