"Finished" minecart hardcoding (still untested and buggy)

This commit is contained in:
MascaraSnake 2019-06-14 21:19:52 +02:00
parent db66f58f2b
commit 018fb9b461
4 changed files with 507 additions and 11 deletions

View File

@ -2428,16 +2428,16 @@ state_t states[NUMSTATES] =
{SPR_ADST, 6|FF_ANIMATE, 24, {NULL}, 3, 8, S_NULL}, // S_ARIDDUST3
// Minecart
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_MINECART_IDLE}, // S_MINECART_IDLE
{SPR_NULL, 0, 45, {NULL}, 0, 0, S_NULL}, // S_MINECART_DTH1
{SPR_MCRT, 8|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_MINECARTEND
{SPR_MCRT, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_MINECARTSEG_FRONT
{SPR_MCRT, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_MINECARTSEG_BACK
{SPR_MCRT, 2|FF_PAPERSPRITE, -1, {NULL}, 2, 3, S_NULL}, // S_MINECARTSEG_LEFT
{SPR_MCRT, 5|FF_PAPERSPRITE, -1, {NULL}, 2, 3, S_NULL}, // S_MINECARTSEG_RIGHT
{SPR_LCKN, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_MINECARTSIDEMARK1
{SPR_LCKN, 0|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_MINECARTSIDEMARK2
{SPR_MCSP, FF_FULLBRIGHT, 1, {A_MinecartSparkThink}, 0, 0, S_MINECARTSPARK}, // S_MINECARTSPARK
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_MINECART_IDLE}, // S_MINECART_IDLE
{SPR_NULL, 0, 45, {NULL}, 0, 0, S_NULL}, // S_MINECART_DTH1
{SPR_MCRT, 8|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_MINECARTEND
{SPR_MCRT, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_MINECARTSEG_FRONT
{SPR_MCRT, 1|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_MINECARTSEG_BACK
{SPR_MCRT, 2|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_MINECARTSEG_LEFT
{SPR_MCRT, 5|FF_PAPERSPRITE|FF_ANIMATE, -1, {NULL}, 2, 3, S_NULL}, // S_MINECARTSEG_RIGHT
{SPR_LCKN, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_MINECARTSIDEMARK1
{SPR_LCKN, 0|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_MINECARTSIDEMARK2
{SPR_MCSP, FF_FULLBRIGHT, 1, {A_MinecartSparkThink}, 0, 0, S_MINECARTSPARK}, // S_MINECARTSPARK
// Saloon door
{SPR_SALD, 0|FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SALOONDOOR

View File

@ -229,6 +229,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state);
boolean P_SetMobjState(mobj_t *mobj, statenum_t state);
void P_RunShields(void);
void P_RunOverlays(void);
void P_HandleMinecartSegments(mobj_t *mobj);
void P_MobjThinker(mobj_t *mobj);
boolean P_RailThinker(mobj_t *mobj);
void P_PushableThinker(mobj_t *mobj);

View File

@ -6728,6 +6728,67 @@ static void P_KoopaThinker(mobj_t *koopa)
}
}
// Spawns and chains the minecart sides.
static void P_SpawnMinecartSegments(mobj_t *mobj, boolean mode)
{
fixed_t x = mobj->x;
fixed_t y = mobj->y;
fixed_t z = mobj->z;
mobj_t *prevseg = mobj;
mobj_t *seg;
UINT8 i;
for (i = 0; i < 4; i++)
{
seg = P_SpawnMobj(x, y, z, MT_PARTICLE);
P_SetMobjState(seg, (statenum_t)(S_MINECARTSEG_FRONT + i));
if (i >= 2)
seg->extravalue1 = (i == 2) ? -18 : 18;
else
{
seg->extravalue2 = (i == 0) ? 24 : -24;
seg->cusval = -90;
}
if (mode)
seg->frame &= ~FF_ANIMATE;
P_SetTarget(&prevseg->tracer, seg);
prevseg = seg;
}
}
// Updates the chained segments.
static void P_UpdateMinecartSegments(mobj_t *mobj)
{
mobj_t *seg = mobj->tracer;
fixed_t x = mobj->x;
fixed_t y = mobj->y;
fixed_t z = mobj->z;
angle_t ang = mobj->angle;
angle_t fa = (ang >> ANGLETOFINESHIFT) & FINEMASK;
fixed_t c = FINECOSINE(fa);
fixed_t s = FINESINE(fa);
INT32 dx, dy;
INT32 sang;
while (seg)
{
dx = seg->extravalue1;
dy = seg->extravalue2;
sang = seg->cusval;
P_TeleportMove(seg, x + s*dx + c*dy, y - c*dx + s*dy, z);
seg->angle = ang + FixedAngle(FRACUNIT*sang);
seg->flags2 = (seg->flags2 & ~MF2_DONTDRAW) | (mobj->flags2 & MF2_DONTDRAW);
seg = seg->tracer;
}
}
void P_HandleMinecartSegments(mobj_t *mobj)
{
if (!mobj->tracer)
P_SpawnMinecartSegments(mobj, (mobj->type == MT_MINECART));
P_UpdateMinecartSegments(mobj);
}
//
// P_MobjThinker
//
@ -8496,6 +8557,7 @@ void P_MobjThinker(mobj_t *mobj)
break;
}
case MT_MINECARTSPAWNER:
P_HandleMinecartSegments(mobj);
if (!mobj->fuse || mobj->fuse > TICRATE)
break;
if (mobj->fuse == 2)
@ -8505,6 +8567,14 @@ void P_MobjThinker(mobj_t *mobj)
}
mobj->flags2 ^= MF2_DONTDRAW;
break;
case MT_MINECART:
// If player is ded, remove this minecart
if (!mobj->target || P_MobjWasRemoved(mobj->target) || !mobj->target->health)
{
P_KillMobj(mobj, NULL, NULL, 0);
return;
}
break;
case MT_SPINFIRE:
if (mobj->flags & MF_NOGRAVITY)
{

View File

@ -9753,6 +9753,421 @@ void P_DoPityCheck(player_t *player)
}
}
static sector_t *P_GetMinecartSector(fixed_t x, fixed_t y, fixed_t z)
{
sector_t *sec = R_PointInSubsector(x, y)->sector;
if ((sec->ceilingheight - sec->floorheight) < 64*FRACUNIT)
return NULL;
if (sec->ffloors)
{
ffloor_t *rover;
for (rover = sec->ffloors; rover; rover = rover->next)
{
if (!(rover->flags & FF_EXISTS))
continue;
fixed_t fofz = rover->t_slope ? P_GetZAt(*rover->t_slope, x, y) : *rover->topheight;
if (abs(z - fofz) <= 40*FRACUNIT)
{
sec = &sectors[rover->secnum];
break;
}
}
}
return sec;
}
static size_t P_GetMinecartSpecialLine(sector_t *sec)
{
size_t line = -1;
if (!sec)
return -1;
if (sec->tag != 0)
line = P_FindSpecialLineFromTag(16, sec->tag, -1);
// Also try for lines facing the sector itself, with tag 0.
if (line == -1)
{
UINT32 i;
for (i = 0; i < sec->linecount; i++)
{
line_t *li = sec->lines[i];
if (li->tag == 0 && li->special == 16 && li->frontsector == sec)
line = i;
}
}
return line;
}
// Get an axis of a certain ID number
static mobj_t *P_GetAxis(UINT16 num)
{
thinker_t *th;
mobj_t *mobj;
for (th = thinkercap.next; th != &thinkercap; th = th->next)
{
if (th->function.acp1 != (actionf_p1)P_MobjThinker)
continue;
mobj = (mobj_t *)th;
// NiGHTS axes spawn before anything else. If this mobj doesn't have MF2_AXIS, it means we reached the axes' end.
if (!(mobj->flags2 & MF2_AXIS))
break;
// Skip if this axis isn't the one we want.
if (!mobj->spawnpoint || mobj->spawnpoint->options != num)
continue;
return mobj;
}
CONS_Debug(DBG_GAMELOGIC, "P_GetAxis: Track segment %d is missing!\n", num);
return NULL;
}
// Auxiliary function. For a given position and axis, it calculates the nearest "valid" snap-on position.
static void P_GetAxisPosition(fixed_t x, fixed_t y, mobj_t *amo, fixed_t *newx, fixed_t *newy, angle_t *targetangle, angle_t *grind)
{
fixed_t ax = amo->x;
fixed_t ay = amo->y;
angle_t ang;
angle_t gr = 0;
if (amo->type == MT_AXISTRANSFERLINE)
{
ang = amo->angle;
// Extra security for cardinal directions.
if (ang == ANGLE_90 || ang == ANGLE_270) // Vertical lines
x = ax;
else if (ang == 0 || ang == ANGLE_180) // Horizontal lines
y = ay;
else // Diagonal lines
{
fixed_t distance = R_PointToDist2(ax, ay, x, y);
angle_t fad = ((R_PointToAngle2(ax, ay, x, y) - ang) >> ANGLETOFINESHIFT) & FINEMASK;
fixed_t cosine = FINECOSINE(fad);
angle_t fa = (ang >> ANGLETOFINESHIFT) & FINEMASK;
distance = FixedMul(distance, cosine);
x = ax + FixedMul(distance, FINECOSINE(fa));
y = ay + FixedMul(distance, FINESINE(fa));
}
}
else // Keep minecart to circle
{
fixed_t rad;
fixed_t distfactor;
gr = R_PointToAngle2(ax, ay, x, y);
ang = gr + ANGLE_90;
if (amo->spawnpoint->angle < 16384) // Counterclockwise
rad = amo->spawnpoint->angle*FRACUNIT;
else // Clockwise
rad = (amo->spawnpoint->angle - 16384)*FRACUNIT;
distfactor = FixedDiv(rad, R_PointToDist2(ax, ay, x, y));
x = ax + FixedMul(x - ax, distfactor);
y = ay + FixedMul(y - ay, distfactor);
}
*newx = x;
*newy = y;
*targetangle = ang;
*grind = gr;
}
static void P_SpawnSparks(mobj_t *mo, angle_t maindir)
{
angle_t fa = (mo->angle >> ANGLETOFINESHIFT) & FINEMASK;
fixed_t c = FixedMul(FINECOSINE(fa), mo->radius);
fixed_t s = FixedMul(FINESINE(fa), mo->radius);
mobj_t *spark;
UINT8 b1 = (leveltime % 2 == 1) ? 1 : -1;
UINT8 b2 = ((leveltime / 2) % 2 == 1) ? 1 : -1;
fixed_t r = FRACUNIT*P_RandomRange(-1, 1);
spark = P_SpawnMobj(mo->x - b2*s + b1*c, mo->y + b2*c + b1*s, mo->z, MT_MINECARTSPARK);
spark->momx = mo->momx + r;
spark->momy = mo->momy + r;
spark->momz = mo->momz + r;
if (maindir)
{
fixed_t fm = (maindir >> ANGLETOFINESHIFT) & FINEMASK;
spark->momx += 8*FINECOSINE(fm);
spark->momy += 8*FINESINE(fm);
}
P_Thrust(spark, R_PointToAngle2(mo->x, mo->y, spark->x, spark->y), 8*FRACUNIT);
P_SetScale(spark, FRACUNIT/4);
spark->fuse = TICRATE/3;
}
// Performs a proximity check on a given direction looking for rails.
static mobj_t *P_LookForRails(mobj_t* mobj, fixed_t c, fixed_t s, angle_t targetangle, fixed_t xcom, fixed_t ycom)
{
INT16 interval = 16;
INT16 fwooffset = FixedHypot(mobj->momx, mobj->momy) >> FRACBITS;
fixed_t x = mobj->x;
fixed_t y = mobj->y;
fixed_t z = mobj->z + 40*FRACUNIT;
UINT8 i;
for (i = 4; i <= 10; i++)
{
fixed_t nz;
size_t lline;
x += interval*xcom*i + fwooffset*c*i;
y += interval*ycom*i + fwooffset*s*i;
nz = P_FloorzAtPos(x, y, z, mobj->height);
lline = P_GetMinecartSpecialLine(P_GetMinecartSector(x, y, nz));
if (lline != -1)
{
fixed_t nx, ny;
angle_t nang, dummy, angdiff;
mobj_t *mark;
mobj_t *snax = P_GetAxis(sides[lines[lline].sidenum[0]].textureoffset >> FRACBITS);
P_GetAxisPosition(x, y, snax, &ny, &nx, &nang, &dummy);
angdiff = nang - targetangle;
if (angdiff < ANG10/2 || angdiff > ANGLE_MAX - ANG10/2)
{
mark = P_SpawnMobj(nx, ny, nz, mobj->info->raisestate);
return mark;
}
}
}
return NULL;
}
static void P_ParabolicMove(mobj_t *mo, fixed_t x, fixed_t y, fixed_t z, fixed_t gravity, fixed_t speed)
{
fixed_t dx = x - mo->x;
fixed_t dy = y - mo->y;
fixed_t dz = z - mo->z;
fixed_t dh = P_AproxDistance(dx, dy);
fixed_t c = FixedDiv(dx, dh);
fixed_t s = FixedDiv(dy, dh);
fixed_t fixConst = FixedDiv(speed, gravity);
mo->momx = FixedMul(c, speed);
mo->momy = FixedMul(s, speed);
mo->momz = FixedDiv(dh, 2*fixConst) + FixedDiv(dz, FixedDiv(dh, fixConst/2));
}
static void P_MinecartThink(player_t *player)
{
mobj_t *minecart = player->mo->tracer;
angle_t fa;
if (!minecart || !P_MobjWasRemoved(minecart) || !minecart->health)
{
// Minecart died on you, so kill yourself.
P_KillMobj(player->mo, NULL, NULL, 0);
return;
}
#if 0
//Limit player's angle to a cone.
#define MINECARTCONEMAX FixedAngle(20*FRACUNIT)
{
angle_t angdiff = player->mo->angle - minecart->angle;
if (angdiff < ANGLE_180 && angdiff > MINECARTCONEMAX)
player->mo->angle = minecart->angle + MINECARTCONEMAX;
else if (angdiff > ANGLE_180 && angdiff < InvAngle(MINECARTCONEMAX))
player->mo->angle = minecart->angle - MINECARTCONEMAX;
if (angdiff + minecart->angle != player->mo->angle)
{
if (player == &players[consoleplayer])
localangle = player->mo->angle;
else if (player == &players[secondarydisplayplayer])
localangle2 = player->mo->angle;
}
}
#endif
//P_ResetPlayer(player);
// Player holding jump?
if (player->cmd.buttons & BT_JUMP)
player->pflags |= PF_JUMPDOWN;
else
player->pflags &= ~PF_JUMPDOWN;
// Handle segments.
P_HandleMinecartSegments(minecart);
// Force 0 friction.
minecart->friction = FRACUNIT;
fa = (minecart->angle >> ANGLETOFINESHIFT) & FINEMASK;
if (!P_TryMove(minecart, minecart->x + FINECOSINE(fa), minecart->y + FINESINE(fa), true))
{
P_KillMobj(player->mo, NULL, NULL, 0);
P_KillMobj(minecart, NULL, NULL, 0);
return;
}
if (P_IsObjectOnGround(minecart))
{
sector_t *sec;
size_t lnum;
// Just hit floor.
if (minecart->eflags & MFE_JUSTHITFLOOR)
{
S_StopSound(minecart);
S_StartSound(minecart, sfx_s3k96);
}
sec = P_GetMinecartSector(minecart->x, minecart->y, minecart->z);
if (sec)
lnum = P_GetMinecartSpecialLine(sec);
// Update axis if the cart is standing on a rail.
if (sec && lnum != -1)
{
mobj_t *axis = P_GetAxis(sides[lines[lnum].sidenum[0]].textureoffset >> FRACBITS);
fixed_t newx, newy;
angle_t targetangle, grind;
angle_t prevangle, angdiff;
mobj_t *detleft = NULL;
mobj_t *detright = NULL;
mobj_t *sidelock = NULL;
boolean jumped = false;
fixed_t currentSpeed;
minecart->movefactor = 0;
P_ResetScore(player);
// Handle angle and position
P_GetAxisPosition(minecart->x, minecart->y, axis, &newx, &newy, &targetangle, &grind);
if (grind)
P_SpawnSparks(minecart, grind);
P_TryMove(minecart, newx, newy, true);
// Set angle based on target
prevangle = minecart->angle;
angdiff = targetangle - minecart->angle;
if (angdiff < ANGLE_90 + ANG2 || angdiff > ANGLE_270 - ANG2)
minecart->angle = targetangle;
else
minecart->angle = targetangle + ANGLE_180;
player->mo->angle += (minecart->angle - prevangle); // maintain relative angle on turns
if (angdiff + minecart->angle != targetangle)
{
if (player == &players[consoleplayer])
localangle = player->mo->angle;
else if (player == &players[secondarydisplayplayer])
localangle2 = player->mo->angle;
}
// Sideways detection
if (minecart->flags2 & MF2_AMBUSH)
{
angle_t fa = minecart->angle;
fixed_t c = FINECOSINE(fa);
fixed_t s = FINESINE(fa);
detleft = P_LookForRails(minecart, c, s, targetangle, -s, c);
detright = P_LookForRails(minecart, c, s, targetangle, s, -c);
}
// How fast are we going?
currentSpeed = FixedHypot(minecart->momx, minecart->momy);
angdiff = R_PointToAngle2(0, 0, minecart->momx, minecart->momy) - minecart->angle;
if (angdiff > ANGLE_90 && angdiff < ANGLE_270)
currentSpeed *= -1;
// Player-specific behavior.
// Update side hopper marker sprites if pressing strafe.
if (detleft && player->cmd.sidemove < 0)
{
P_SetMobjState(detleft, detleft->info->seestate);
sidelock = detleft;
}
else if (detright && player->cmd.sidemove > 0)
{
P_SetMobjState(detright, detright->info->seestate);
sidelock = detright;
}
//if (player->cmd.buttons & BT_USE && currentSpeed > 4*FRACUNIT)
// currentSpeed -= FRACUNIT/8;
// Jumping
if (player->cmd.buttons & BT_JUMP)
{
if (minecart->eflags & MFE_ONGROUND)
minecart->eflags &= ~MFE_ONGROUND;
minecart->z += P_MobjFlip(minecart);
if (sidelock)
P_ParabolicMove(minecart, sidelock->x, sidelock->y, sidelock->z, gravity, max(currentSpeed, 10 * FRACUNIT));
else
minecart->momz = 10 * FRACUNIT;
S_StartSound(minecart, sfx_s3k51);
jumped = true;
}
if (!jumped)
{
// Natural acceleration and boosters
if (currentSpeed < minecart->info->seesound)
currentSpeed += FRACUNIT/4;
if (minecart->standingslope)
{
fa = (minecart->angle >> ANGLETOFINESHIFT) & FINEMASK;
fixed_t front = P_GetZAt(minecart->standingslope, minecart->x, minecart->y);
fixed_t back = P_GetZAt(minecart->standingslope, minecart->x - FINECOSINE(fa), minecart->y - FINESINE(fa));
if (abs(front - back) < 3*FRACUNIT)
currentSpeed += (back - front)/3;
}
// Go forward at our current speed
P_InstaThrust(minecart, minecart->angle, currentSpeed);
// On-track ka-klong sound FX.
minecart->movecount += abs(currentSpeed);
if (minecart->movecount > 128*FRACUNIT)
{
minecart->movecount %= 128*FRACUNIT;
S_StartSound(minecart, minecart->info->activesound);
}
}
}
else
{
minecart->movefactor++;
if ((P_IsObjectOnGround(minecart) && minecart->movefactor >= 5) // off rail
|| (abs(minecart->momx) < minecart->scale/2 && abs(minecart->momy) < minecart->scale/2)) // hit a wall
{
P_KillMobj(player->mo, NULL, NULL, 0);
P_KillMobj(minecart, NULL, NULL, 0);
return;
}
}
}
P_SetMobjState(player->mo, S_PLAY_STND);
// Move player to minecart.
P_TeleportMove(player->mo, minecart->x - minecart->momx, minecart->y - minecart->momy, minecart->z + max(minecart->momz, 0) + 8*FRACUNIT);
player->mo->momx = minecart->momx;
player->mo->momy = minecart->momy;
player->mo->momz = 0;
P_TryMove(player->mo, player->mo->x + minecart->momx, player->mo->y + minecart->momy, true);
}
//
// P_PlayerThink
//
@ -10052,6 +10467,8 @@ void P_PlayerThink(player_t *player)
// for a bit after a teleport.
if (player->mo->reactiontime)
player->mo->reactiontime--;
else if (player->powers[pw_carry] == CR_MINECART)
P_MinecartThink(player);
else if (player->mo->tracer && player->mo->tracer->type == MT_TUBEWAYPOINT && (player->powers[pw_carry] == CR_ROPEHANG || player->powers[pw_carry] == CR_ZOOMTUBE))
{
if (player->powers[pw_carry] == CR_ROPEHANG)
@ -10113,7 +10530,15 @@ void P_PlayerThink(player_t *player)
switch (player->powers[pw_carry])
{
case CR_PLAYER:
player->drawangle = (player->mo->tracer->player ? player->mo->tracer->player->drawangle : player->mo->tracer->angle);
if (player->mo->tracer->player)
{
player->drawangle = player->mo->tracer->player->drawangle;
break;
}
/* FALLTHRU */
case CR_MINECART:
case CR_GENERIC:
player->drawangle = player->mo->tracer->angle;
break;
/* -- in case we wanted to have the camera freely movable during zoom tubes
case CR_ZOOMTUBE:*/