diff --git a/src/g_game.c b/src/g_game.c index 522777ee5..6ea14bcff 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -428,9 +428,18 @@ consvar_t cv_cam_lockedinput[2] = { {"cam2_lockedinput", "Strafe", CV_SAVE, lockedinput_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}, }; +static CV_PossibleValue_t lockedassist_cons_t[] = { + {0, "Off"}, + {LOCK_BOSS, "Bosses"}, + {LOCK_BOSS|LOCK_ENEMY, "Enemies"}, + {LOCK_BOSS|LOCK_INTERESTS, "Interests"}, + {LOCK_BOSS|LOCK_ENEMY|LOCK_INTERESTS, "Full"}, + {0, NULL} +}; + consvar_t cv_cam_lockonboss[2] = { - {"cam_lockonboss", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}, - {"cam2_lockonboss", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}, + {"cam_lockaimassist", "Bosses", CV_SAVE, lockedassist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}, + {"cam2_lockaimassist", "Bosses", CV_SAVE, lockedassist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}, }; typedef enum @@ -1286,7 +1295,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) *myaiming = 0; if (cv_cam_lockonboss[forplayer].value) - P_SetTarget(&ticcmd_ztargetfocus[forplayer], P_LookForFocusTarget(player, NULL, 0)); + P_SetTarget(&ticcmd_ztargetfocus[forplayer], P_LookForFocusTarget(player, NULL, 0, cv_cam_lockonboss[forplayer].value)); } ticcmd_centerviewdown[forplayer] = true; diff --git a/src/g_game.h b/src/g_game.h index f6e7acede..0a018e253 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -81,6 +81,14 @@ extern consvar_t cv_abilitydirection[2], cv_cam_shiftfacing[2], cv_cam_turnfacin cv_cam_turnfacingability[2], cv_cam_turnfacingspindash[2], cv_cam_turnfacinginput[2], cv_cam_lockedinput[2], cv_cam_lockonboss[2]; +typedef enum +{ + LOCK_BOSS = 1<<0, + LOCK_ENEMY = 1<<1, + LOCK_INTERESTS = 1<<2, +} lockassist_e; + + // mouseaiming (looking up/down with the mouse or keyboard) #define KB_LOOKSPEED (1<<25) #define MAXPLMOVE (50) diff --git a/src/m_menu.c b/src/m_menu.c index 6d42fddda..bfe118af1 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -1239,7 +1239,7 @@ static menuitem_t OP_CameraExtendedOptionsMenu[] = {IT_HEADER, NULL, "Locked Camera Options", NULL, 95}, {IT_STRING | IT_CVAR, NULL, "Sideways movement", &cv_cam_lockedinput[0], 100}, - {IT_STRING | IT_CVAR, NULL, "Boss targeting assist", &cv_cam_lockonboss[0], 105}, + {IT_STRING | IT_CVAR, NULL, "Targeting assist", &cv_cam_lockonboss[0], 105}, {IT_HEADER, NULL, "Display Options", NULL, 115}, {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair, 120}, @@ -1268,7 +1268,7 @@ static menuitem_t OP_Camera2ExtendedOptionsMenu[] = {IT_HEADER, NULL, "Locked Camera Options", NULL, 95}, {IT_STRING | IT_CVAR, NULL, "Sideways movement", &cv_cam_lockedinput[1], 100}, - {IT_STRING | IT_CVAR, NULL, "Boss targeting assist", &cv_cam_lockonboss[1], 105}, + {IT_STRING | IT_CVAR, NULL, "Targeting assist", &cv_cam_lockonboss[1], 105}, {IT_HEADER, NULL, "Display Options", NULL, 115}, {IT_STRING | IT_CVAR, NULL, "Crosshair", &cv_crosshair2, 120}, diff --git a/src/p_local.h b/src/p_local.h index f87930e28..ee52ac808 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -181,7 +181,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); -mobj_t *P_LookForFocusTarget(player_t *player, mobj_t *exclude, SINT8 direction); +mobj_t *P_LookForFocusTarget(player_t *player, mobj_t *exclude, SINT8 direction, UINT8 lockonflags); mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet); void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius); diff --git a/src/p_user.c b/src/p_user.c index e57c56aa4..9c4c8a100 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -9142,7 +9142,7 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius) // direction, if set, requires the target to be to the left (1) or right (-1) of the angle // mobjflags can be used to limit the flags of objects that can be focused // -mobj_t *P_LookForFocusTarget(player_t *player, mobj_t *exclude, SINT8 direction) +mobj_t *P_LookForFocusTarget(player_t *player, mobj_t *exclude, SINT8 direction, UINT8 lockonflags) { mobj_t *mo; thinker_t *think; @@ -9162,20 +9162,53 @@ mobj_t *P_LookForFocusTarget(player_t *player, mobj_t *exclude, SINT8 direction) if (mo->flags & MF_NOCLIPTHING) continue; - if (mo->health <= 0) // dead - continue; - - if (!(mo->flags & MF_BOSS && (mo->flags & MF_SHOOTABLE)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag - continue; // not a valid target - if (mo == player->mo) continue; - if (mo->flags2 & MF2_FRET) + if (mo->health <= 0) // dead continue; - if (mo->type == MT_DETON) // Don't be STUPID, Sonic! - continue; + switch (mo->type) + { + case MT_TNTBARREL: + if (lockonflags & LOCK_INTERESTS) + break; + /*fallthru*/ + case MT_PLAYER: // Don't chase other players! + case MT_DETON: + continue; // Don't be STUPID, Sonic! + + case MT_FAKEMOBILE: + if (!(lockonflags & LOCK_BOSS)) + continue; + break; + + case MT_EGGSHIELD: + if (!(lockonflags & LOCK_ENEMY)) + continue; + break; + + case MT_EGGSTATUE: + if (tutorialmode) + break; // Always focus egg statue in the tutorial + /*fallthru*/ + default: + + if ((lockonflags & LOCK_BOSS) && ((mo->flags & (MF_BOSS|MF_SHOOTABLE)) == (MF_BOSS|MF_SHOOTABLE))) // allows if it has the flags desired XOR it has the invert aimable flag + { + if (mo->flags2 & MF2_FRET) + continue; + break; + } + + if ((lockonflags & LOCK_ENEMY) && (!((mo->flags & (MF_ENEMY|MF_SHOOTABLE)) == (MF_ENEMY|MF_SHOOTABLE)) != !(mo->flags2 & MF2_INVERTAIMABLE))) // allows if it has the flags desired XOR it has the invert aimable flag + break; + + if ((lockonflags & LOCK_INTERESTS) && (mo->flags & (MF_PUSHABLE|MF_MONITOR))) // allows if it has the flags desired XOR it has the invert aimable flag + break; + + continue; // not a valid object + } { fixed_t zdist = (player->mo->z + player->mo->height/2) - (mo->z + mo->height/2); @@ -9193,13 +9226,9 @@ mobj_t *P_LookForFocusTarget(player_t *player, mobj_t *exclude, SINT8 direction) && abs(player->mo->y-mo->y) > player->mo->radius) continue; // not in your 2d plane - if (mo->type == MT_PLAYER) // Don't chase after other players! - continue; - - dangle = R_PointToAngle2(player->mo->x + P_ReturnThrustX(player->mo, player->mo->angle, player->mo->radius), player->mo->y + P_ReturnThrustY(player->mo, player->mo->angle, player->mo->radius), mo->x, mo->y) - player->mo->angle; - - if ((dangle + span) > span*2) - continue; // behind back + dangle = R_PointToAngle2(player->mo->x, player->mo->y, mo->x, mo->y) - ( + !exclude ? player->mo->angle : R_PointToAngle2(player->mo->x, player->mo->y, exclude->x, exclude->y) + ); if (direction) { @@ -9209,6 +9238,15 @@ mobj_t *P_LookForFocusTarget(player_t *player, mobj_t *exclude, SINT8 direction) continue; // To the left of the player } + if (dangle > ANGLE_180) + dangle = InvAngle(dangle); + + if (dangle > span) + continue; // behind back + + // Inflate dist by angle difference to bias toward objects at a closer angle + dist = FixedDiv(dist, FINECOSINE(dangle>>ANGLETOFINESHIFT)*3); + if (closestmo && (exclude ? (dangle > closestdangle) : (dist > closestdist))) continue;