After usability complaints:

* CA2_MELEE/CA_TWINSPIN combination abilities (ground hit, somersalt) disabled.
* Enabled movement controls whilst using CA2_MELEE in the air.
* CA2_GUNSLINGER no longer requires charging. In exchange, it involves a cooldown in which you can't move.
* CA2_GUNSLINGER lock-on distance improved, and aiming allowance reduced to compensate.
* Lots of cleanup/gravflip allowances for homing/targeting code.

* Unrelated: Flickies now properly face the direction they're supposed to when getting knocked out of the egg capsule.
* Unrelated: Thok trail fades like spindash trail now.
* Unrelated: Using CA_HOMINGATTACK when nowhere near an enemy uncurls you.
This commit is contained in:
toasterbabe 2017-03-21 16:04:49 +00:00
parent 9d9f3e5e1a
commit 7ac0373dbf
7 changed files with 80 additions and 93 deletions

View File

@ -3937,8 +3937,8 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_PLAY_BOUNCE_LANDING",
// CA2_GUNSLINGER
"S_PLAY_CHARGE",
"S_PLAY_FIRE",
"S_PLAY_FIRE_FINISH",
// CA_TWINSPIN
"S_PLAY_TWINSPIN",

View File

@ -419,7 +419,6 @@ char spr2names[NUMPLAYERSPRITES][5] =
"BNCE",
"BLND",
"CHRG",
"FIRE",
"TWIN",
@ -533,8 +532,8 @@ state_t states[NUMSTATES] =
{SPR_PLAY, SPR2_BLND|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_BOUNCE, 0, S_PLAY_BOUNCE_LANDING}, // S_PLAY_BOUNCE_LANDING
// CA2_GUNSLINGER
{SPR_PLAY, SPR2_CHRG, 2, {NULL}, 0, 0, S_PLAY_CHARGE}, // S_PLAY_CHARGE
{SPR_PLAY, SPR2_FIRE|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_STND, 0, S_PLAY_FIRE}, // S_PLAY_FIRE
{SPR_PLAY, SPR2_FIRE|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_FIRE_FINISH, 0, S_PLAY_FIRE}, // S_PLAY_FIRE
{SPR_PLAY, SPR2_FIRE, 15, {NULL}, S_PLAY_STND, 0, S_PLAY_STND}, // S_PLAY_FIRE_FINISH
// CA_TWINSPIN
{SPR_PLAY, SPR2_TWIN|FF_SPR2ENDSTATE, 1, {NULL}, S_PLAY_JUMP, 0, S_PLAY_TWINSPIN}, // S_PLAY_TWINSPIN

View File

@ -632,7 +632,6 @@ enum playersprite
SPR2_BNCE, // bounce
SPR2_BLND, // bounce landing
SPR2_CHRG, // charge
SPR2_FIRE, // fire
SPR2_TWIN, // twinspin
@ -743,8 +742,8 @@ typedef enum state
S_PLAY_BOUNCE_LANDING,
// CA2_GUNSLINGER
S_PLAY_CHARGE,
S_PLAY_FIRE,
S_PLAY_FIRE_FINISH,
// CA_TWINSPIN
S_PLAY_TWINSPIN,

View File

@ -1055,12 +1055,12 @@ static int lib_pLookForEnemies(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
boolean nonenemies = lua_opttrueboolean(L, 2);
boolean abovehorizontal = lua_opttrueboolean(L, 3);
boolean bullet = lua_opttrueboolean(L, 3);
NOHUD
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, P_LookForEnemies(player, nonenemies, abovehorizontal));
lua_pushboolean(L, P_LookForEnemies(player, nonenemies, bullet));
return 1;
}

View File

@ -174,7 +174,7 @@ fixed_t P_ReturnThrustX(mobj_t *mo, angle_t angle, fixed_t move);
fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move);
void P_InstaThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move);
boolean P_LookForEnemies(player_t *player, boolean nonenemies, boolean abovehorizontal);
boolean P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet);
void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius);
void P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user
boolean P_SuperReady(player_t *player);

View File

@ -280,10 +280,6 @@ UINT8 P_GetMobjSprite2(mobj_t *mobj, UINT8 spr2)
spr2 = SPR2_ROLL;
break;
case SPR2_FIRE:
spr2 = SPR2_CHRG;
break;
case SPR2_TWIN:
spr2 = SPR2_ROLL;
break;
@ -474,8 +470,8 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
player->panim = PA_ABILITY;
break;
case S_PLAY_SPINDASH: // ...but the act of SPINDASHING is charability2 specific.
case S_PLAY_CHARGE:
case S_PLAY_FIRE:
case S_PLAY_FIRE_FINISH:
case S_PLAY_MELEE:
case S_PLAY_MELEE_FINISH:
case S_PLAY_MELEE_LANDING:
@ -523,7 +519,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
else
mobj->tics = 1;
}
else if (player->panim == PA_ABILITY2 && (player->charability2 == CA2_SPINDASH || state == S_PLAY_CHARGE))
else if (player->panim == PA_ABILITY2 && player->charability2 == CA2_SPINDASH)
{
fixed_t step = (player->maxdash - player->mindash)/4;
speed = (player->dashspeed - player->mindash);
@ -3210,18 +3206,19 @@ static void P_PlayerZMovement(mobj_t *mo)
}
}
if (mo->health)
if (mo->health && !P_CheckDeathPitCollide(mo))
{
if (mo->player->pflags & PF_GLIDING) // ground gliding
{
mo->player->skidtime = TICRATE;
mo->tics = -1;
}
else if (mo->player->charability2 == CA2_MELEE && ((mo->player->charability == CA_TWINSPIN && mo->player->panim == PA_ABILITY) || (mo->player->panim == PA_ABILITY2 && mo->state-states != S_PLAY_MELEE_LANDING)))
else if (mo->player->charability2 == CA2_MELEE && (mo->player->panim == PA_ABILITY2 && mo->state-states != S_PLAY_MELEE_LANDING))
{
P_SetPlayerMobjState(mo, S_PLAY_MELEE_LANDING);
mo->tics = (mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(mo->movefactor)))>>FRACBITS;
S_StartSound(mo, sfx_s3k8b);
mo->player->pflags |= PF_FULLSTASIS;
}
else if (mo->player->pflags & PF_JUMPED || (mo->player->pflags & (PF_SPINNING|PF_USEDOWN)) != (PF_SPINNING|PF_USEDOWN)
|| mo->player->powers[pw_tailsfly] || mo->state-states == S_PLAY_FLY_TIRED)
@ -3302,7 +3299,7 @@ static void P_PlayerZMovement(mobj_t *mo)
}
}
if (mo->player->pflags & PF_BOUNCING && !P_CheckDeathPitCollide(mo))
if (mo->player->pflags & PF_BOUNCING)
{
mo->momz *= -1;
P_DoAbilityBounce(mo->player, true);
@ -7276,7 +7273,6 @@ void P_MobjThinker(mobj_t *mobj)
ns = 4 * FRACUNIT;
mo2->momx = FixedMul(FINESINE(fa),ns);
mo2->momy = FixedMul(FINECOSINE(fa),ns);
mo2->angle = fa << ANGLETOFINESHIFT;
if (P_RandomChance(FRACUNIT/4)) // I filled a spreadsheet trying to get the equivalent chance to the original P_RandomByte hack!
S_StartSound(mo2, mobj->info->deathsound);
@ -7288,6 +7284,7 @@ void P_MobjThinker(mobj_t *mobj)
P_SetTarget(&flicky->target, mo2);
flicky->momx = mo2->momx;
flicky->momy = mo2->momy;
flicky->angle = fa << ANGLETOFINESHIFT;
}
mobj->fuse--;

View File

@ -1576,6 +1576,12 @@ void P_SpawnThokMobj(player_t *player)
// scale
P_SetScale(mobj, player->mo->scale);
mobj->destscale = player->mo->scale;
if (type == MT_THOK) // spintrail-specific modification for MT_THOK
{
mobj->frame = FF_TRANS70;
mobj->fuse = mobj->tics;
}
}
P_SetTarget(&mobj->target, player->mo); // the one thing P_SpawnGhostMobj doesn't do
@ -3842,59 +3848,43 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
}
break;
case CA2_GUNSLINGER:
if ((cmd->buttons & BT_USE)
&& !player->mo->momz && onground
if ((cmd->buttons & BT_USE) && !(player->pflags & PF_USEDOWN)
&& !player->mo->momz && onground // && !player->weapondelay
&& canstand)
{
if (!player->dashspeed)
{
player->mo->momx = player->cmomx;
player->mo->momy = player->cmomy;
player->pflags |= PF_USEDOWN;
player->dashspeed = player->mindash;
P_SetPlayerMobjState(player->mo, S_PLAY_CHARGE);
if (!player->spectator)
S_StartSound(player->mo, sfx_s3k5a); // Make the rev sound! Previously sfx_spndsh.
}
else if (player->dashspeed < player->maxdash)
player->dashspeed += FRACUNIT;
else if (player->mo->tics != -1)
{
player->mo->tics = -1;
player->mo->frame = 0;
}
}
else if (player->dashspeed && (player->pflags & PF_USEDOWN))
{
mobj_t *cork;
const boolean maxspeed = (player->dashspeed >= player->maxdash);
mobj_t *bullet;
P_SetPlayerMobjState(player->mo, S_PLAY_FIRE);
if (maxspeed && P_LookForEnemies(player, false, true) && player->mo->tracer)
#define zpos(posmo) (posmo->z + (posmo->height - mobjinfo[player->spinitem].height)/2)
if (P_LookForEnemies(player, false, true) && player->mo->tracer)
{
player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, player->mo->target->x, player->mo->target->y);
cork = P_SpawnMissile(player->mo, player->mo->tracer, player->spinitem);
bullet = P_SpawnPointMissile(player->mo, player->mo->tracer->x, player->mo->tracer->y, zpos(player->mo->tracer), player->spinitem, player->mo->x, player->mo->y, zpos(player->mo));
if (!demoplayback || P_AnalogMove(player))
{
if (player == &players[consoleplayer])
localangle = player->mo->angle;
else if (player == &players[secondarydisplayplayer])
localangle2 = player->mo->angle;
}
}
else
{
fixed_t z = (player->mo->z + player->mo->height/2);
if ((cork = P_SpawnPointMissile(player->mo, player->mo->x + P_ReturnThrustX(NULL, player->mo->angle, FRACUNIT), player->mo->y + P_ReturnThrustY(NULL, player->mo->angle, FRACUNIT), z, player->spinitem, player->mo->x, player->mo->y, z)))
bullet = P_SpawnPointMissile(player->mo, player->mo->x + P_ReturnThrustX(NULL, player->mo->angle, FRACUNIT), player->mo->y + P_ReturnThrustY(NULL, player->mo->angle, FRACUNIT), zpos(player->mo), player->spinitem, player->mo->x, player->mo->y, zpos(player->mo));
if (bullet)
{
cork->flags &= ~MF_NOGRAVITY;
if (!maxspeed)
cork->flags |= MF_NOCLIPTHING;
bullet->flags &= ~MF_NOGRAVITY;
bullet->momx >>= 1;
bullet->momy >>= 1;
}
}
if (cork)
{
cork->momx = FixedDiv(FixedMul(cork->momx, player->dashspeed), mobjinfo[player->spinitem].speed);
cork->momy = FixedDiv(FixedMul(cork->momy, player->dashspeed), mobjinfo[player->spinitem].speed);
if (player->mo->tracer)
cork->momz = ((player->mo->tracer->z - player->mo->z) / (P_AproxDistance(player->mo->tracer->x - player->mo->x, player->mo->tracer->y - player->mo->y) / player->dashspeed));
}
#undef zpos
P_SetTarget(&player->mo->tracer, NULL);
player->dashspeed = 0;
player->mo->momx >>= 1;
player->mo->momy >>= 1;
player->pflags |= PF_USEDOWN;
// player->weapondelay = TICRATE/2;
}
break;
case CA2_MELEE: // Melee attack
@ -3903,16 +3893,18 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
&& canstand)
{
P_ResetPlayer(player);
player->pflags |= PF_THOKKED;
#if 0
if ((player->charability == CA_TWINSPIN) && (player->speed > FixedMul(player->runspeed, player->mo->scale)))
{
P_DoJump(player, false);
player->jumping = 0;
player->mo->momz = FixedMul(player->mo->momz, 3*FRACUNIT/2); // NOT 1.5 times the jump height, but 2.25 times.
player->pflags |= PF_THOKKED;
P_SetPlayerMobjState(player->mo, S_PLAY_TWINSPIN);
S_StartSound(player->mo, sfx_s3k8b);
}
else
#endif
{
player->mo->z += P_MobjFlip(player->mo);
P_SetObjectMomZ(player->mo, player->mindash, false);
@ -4265,10 +4257,13 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
if (player->charability == CA_HOMINGTHOK && !player->homing)
{
if (P_LookForEnemies(player, true, false))
player->pflags &= ~PF_NOJUMPDAMAGE;
if (P_LookForEnemies(player, true, false) && player->mo->tracer)
player->homing = 3*TICRATE;
else
{
if (player->mo->tracer)
player->homing = 3*TICRATE;
P_SetPlayerMobjState(player->mo, S_PLAY_FALL);
player->pflags &= ~PF_JUMPED;
}
}
@ -4945,8 +4940,6 @@ static void P_3dMovement(player_t *player)
else
movepushforward = FixedDiv(movepushforward, 16*FRACUNIT);
}
else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2)
movepushforward = 0;
movepushforward = FixedMul(movepushforward, player->mo->scale);
@ -4989,8 +4982,6 @@ static void P_3dMovement(player_t *player)
else
movepushforward = FixedDiv(movepushforward, 16*FRACUNIT);
}
else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2)
movepushforward = 0;
movepushsideangle = controldirection;
@ -5025,8 +5016,6 @@ static void P_3dMovement(player_t *player)
else
movepushside = FixedDiv(movepushside,16*FRACUNIT);
}
else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2)
movepushside = 0;
// Finally move the player now that his speed/direction has been decided.
movepushside = FixedMul(movepushside, player->mo->scale);
@ -6613,8 +6602,8 @@ static void P_MovePlayer(player_t *player)
// Control relinquishing stuff!
if ((player->powers[pw_carry] == CR_BRAKGOOP)
|| (player->pflags & PF_GLIDING && player->skidtime)
|| (player->charability2 == CA2_GUNSLINGER && player->mo->state-states == S_PLAY_FIRE)
|| (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
|| (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2)
|| (player->charability2 == CA2_MELEE && player->mo->state-states == S_PLAY_MELEE_LANDING))
player->pflags |= PF_FULLSTASIS;
else if (player->powers[pw_nocontrol])
{
@ -7871,15 +7860,18 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius)
// P_LookForEnemies
// Looks for something you can hit - Used for homing attack
// If nonenemies is true, includes monitors and springs!
// If abovehorizontal is true, you can look up, but your total vertical range is limited to compensate.
// If bullet is true, you can look up and the distance is further,
// but your total angle span you can look is limited to compensate.
//
boolean P_LookForEnemies(player_t *player, boolean nonenemies, boolean abovehorizontal)
boolean P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
{
mobj_t *mo;
thinker_t *think;
mobj_t *closestmo = NULL;
angle_t an;
const UINT32 targetmask = (MF_ENEMY|MF_BOSS|(nonenemies ? (MF_MONITOR|MF_SPRING) : 0));
const fixed_t maxdist = FixedMul((bullet ? RING_DIST*2 : RING_DIST), player->mo->scale);
const angle_t span = (bullet ? ANG30 : ANGLE_90);
fixed_t dist, closestdist = 0;
for (think = thinkercap.next; think != &thinkercap; think = think->next)
{
@ -7906,11 +7898,11 @@ boolean P_LookForEnemies(player_t *player, boolean nonenemies, boolean abovehori
continue;
{
fixed_t dist = P_AproxDistance(player->mo->x-mo->x, player->mo->y-mo->y);
if (abovehorizontal)
fixed_t zdist = (player->mo->z + player->mo->height/2) - (mo->z + mo->height/2);
dist = P_AproxDistance(player->mo->x-mo->x, player->mo->y-mo->y);
if (bullet)
{
angle_t ang = R_PointToAngle2(0, player->mo->z, dist, mo->z) + ANGLE_45;
angle_t ang = R_PointToAngle2(0, 0, dist, zdist) + ANGLE_45;
if (ang > ANGLE_90)
continue; // Don't home outside of desired angle!
}
@ -7918,15 +7910,15 @@ boolean P_LookForEnemies(player_t *player, boolean nonenemies, boolean abovehori
{
if (player->mo->eflags & MFE_VERTICALFLIP)
{
if (mo->z > player->mo->z+FixedMul(MAXSTEPMOVE, player->mo->scale))
continue;
if (mo->z+mo->height < player->mo->z+player->mo->height-FixedMul(MAXSTEPMOVE, player->mo->scale))
continue;
}
else if (mo->z+mo->height < player->mo->z+player->mo->height-FixedMul(MAXSTEPMOVE, player->mo->scale))
else if (mo->z > player->mo->z+FixedMul(MAXSTEPMOVE, player->mo->scale))
continue;
}
if (P_AproxDistance(dist,
player->mo->z-mo->z) > FixedMul(RING_DIST, player->mo->scale))
dist = P_AproxDistance(dist, zdist);
if (dist > maxdist)
continue; // out of range
}
@ -7937,20 +7929,17 @@ boolean P_LookForEnemies(player_t *player, boolean nonenemies, boolean abovehori
if (mo->type == MT_PLAYER) // Don't chase after other players!
continue;
if (closestmo && P_AproxDistance(P_AproxDistance(player->mo->x-mo->x, player->mo->y-mo->y),
player->mo->z-mo->z) > P_AproxDistance(P_AproxDistance(player->mo->x-closestmo->x,
player->mo->y-closestmo->y), player->mo->z-closestmo->z))
if (closestmo && dist > closestdist)
continue;
an = R_PointToAngle2(player->mo->x, player->mo->y, mo->x, mo->y) - player->mo->angle;
if (an > ANGLE_90 && an < ANGLE_270)
if ((R_PointToAngle2(player->mo->x, player->mo->y, mo->x, mo->y) - player->mo->angle + span) > span*2)
continue; // behind back
if (!P_CheckSight(player->mo, mo))
continue; // out of sight
closestmo = mo;
closestdist = dist;
}
if (closestmo)
@ -7966,6 +7955,7 @@ boolean P_LookForEnemies(player_t *player, boolean nonenemies, boolean abovehori
void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
{
fixed_t zdist;
fixed_t dist;
fixed_t ns = 0;
@ -7986,8 +7976,8 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
}
// change slope
dist = P_AproxDistance(P_AproxDistance(enemy->x - source->x, enemy->y - source->y),
enemy->z - source->z);
zdist = (P_MobjFlip(source) ? (enemy->z + enemy->height) - (source->z + source->height) : (enemy->z - source->z));
dist = P_AproxDistance(P_AproxDistance(enemy->x - source->x, enemy->y - source->y), zdist);
if (dist < 1)
dist = 1;
@ -8011,7 +8001,7 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns);
source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), ns);
source->momz = FixedMul(FixedDiv(enemy->z - source->z, dist), ns);
source->momz = FixedMul(FixedDiv(zdist, dist), ns);
}
// Search for emeralds
@ -9121,7 +9111,9 @@ void P_PlayerThink(player_t *player)
if (player->panim != PA_ABILITY)
P_SetPlayerMobjState(player->mo, S_PLAY_GLIDE);
}
else if ((player->pflags & PF_JUMPED) && !player->powers[pw_super] && ((player->charflags & SF_NOJUMPSPIN && player->pflags & PF_NOJUMPDAMAGE && player->panim != PA_ROLL) || (!(player->charflags & SF_NOJUMPSPIN) && player->panim != PA_JUMP)))
else if ((player->pflags & PF_JUMPED)
&& ((player->charflags & SF_NOJUMPSPIN && !(player->pflags & PF_NOJUMPDAMAGE) && player->panim != PA_ROLL)
|| (!(player->charflags & SF_NOJUMPSPIN) && player->panim != PA_JUMP)))
{
if (!(player->charflags & SF_NOJUMPSPIN))
P_SetPlayerMobjState(player->mo, S_PLAY_JUMP);