diff --git a/src/d_player.h b/src/d_player.h index d7901434f..8db170089 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -75,6 +75,7 @@ typedef enum CA2_NONE=0, CA2_SPINDASH, CA2_MULTIABILITY, + CA2_GUNSLINGER, CA2_MELEE } charability2_t; diff --git a/src/dehacked.c b/src/dehacked.c index a39cf9136..af982662d 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -3908,7 +3908,6 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_PLAY_DEAD", "S_PLAY_DRWN", "S_PLAY_ROLL", - "S_PLAY_SPINDASH", "S_PLAY_GASP", "S_PLAY_JUMP", "S_PLAY_SPRING", @@ -3916,6 +3915,9 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_PLAY_EDGE", "S_PLAY_RIDE", + // CA2_SPINDASH + "S_PLAY_SPINDASH", + // CA_FLY/SWIM "S_PLAY_FLY", "S_PLAY_SWIM", @@ -3934,6 +3936,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit "S_PLAY_BOUNCE", "S_PLAY_BOUNCE_LANDING", + // CA2_GUNSLINGER + "S_PLAY_CHARGE", + "S_PLAY_FIRE", + // CA_TWINSPIN "S_PLAY_TWINSPIN", @@ -7398,6 +7404,7 @@ struct { {"CA2_NONE",CA2_NONE}, // now slot 0! {"CA2_SPINDASH",CA2_SPINDASH}, {"CA2_MULTIABILITY",CA2_MULTIABILITY}, + {"CA2_GUNSLINGER",CA2_GUNSLINGER}, {"CA2_MELEE",CA2_MELEE}, // Sound flags diff --git a/src/info.c b/src/info.c index 60acd2d4b..4434a6908 100644 --- a/src/info.c +++ b/src/info.c @@ -396,7 +396,6 @@ char spr2names[NUMPLAYERSPRITES][5] = "DEAD", "DRWN", "ROLL", - "SPIN", "GASP", "JUMP", "SPNG", @@ -404,6 +403,8 @@ char spr2names[NUMPLAYERSPRITES][5] = "EDGE", "RIDE", + "SPIN", + "FLY_", "SWIM", "TIRE", @@ -418,6 +419,9 @@ char spr2names[NUMPLAYERSPRITES][5] = "BNCE", "BLND", + "CHRG", + "FIRE", + "TWIN", "MLEE", @@ -500,7 +504,6 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_DEAD|FF_ANIMATE, -1, {NULL}, 0, 4, S_NULL}, // S_PLAY_DEAD {SPR_PLAY, SPR2_DRWN|FF_ANIMATE, -1, {NULL}, 0, 4, S_NULL}, // S_PLAY_DRWN {SPR_PLAY, SPR2_ROLL, 1, {NULL}, 0, 0, S_PLAY_ROLL}, // S_PLAY_ROLL - {SPR_PLAY, SPR2_SPIN, 2, {NULL}, 0, 0, S_PLAY_SPINDASH}, // S_PLAY_SPINDASH {SPR_PLAY, SPR2_GASP|FF_ANIMATE, 14, {NULL}, 0, 4, S_PLAY_WALK}, // S_PLAY_GASP {SPR_PLAY, SPR2_JUMP, 1, {NULL}, 0, 0, S_PLAY_JUMP}, // S_PLAY_JUMP {SPR_PLAY, SPR2_SPNG, 2, {NULL}, 0, 0, S_PLAY_SPRING}, // S_PLAY_SPRING @@ -508,6 +511,9 @@ state_t states[NUMSTATES] = {SPR_PLAY, SPR2_EDGE|FF_ANIMATE, -1, {NULL}, 0, 12, S_NULL}, // S_PLAY_EDGE {SPR_PLAY, SPR2_RIDE, 4, {NULL}, 0, 0, S_PLAY_RIDE}, // S_PLAY_RIDE + // CA2_SPINDASH + {SPR_PLAY, SPR2_SPIN, 2, {NULL}, 0, 0, S_PLAY_SPINDASH}, // S_PLAY_SPINDASH + // CA_FLY/CA_SWIM {SPR_PLAY, SPR2_FLY , 2, {NULL}, 0, 0, S_PLAY_FLY}, // S_PLAY_FLY {SPR_PLAY, SPR2_SWIM, 2, {NULL}, 0, 0, S_PLAY_SWIM}, // S_PLAY_SWIM @@ -524,7 +530,11 @@ state_t states[NUMSTATES] = // CA_BOUNCE {SPR_PLAY, SPR2_BNCE|FF_ANIMATE, -1, {NULL}, 0, 0, S_NULL}, // S_PLAY_BOUNCE - {SPR_PLAY, SPR2_BLND|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_BOUNCE, 4, S_PLAY_BOUNCE_LANDING}, // S_PLAY_BOUNCE_LANDING + {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 // CA_TWINSPIN {SPR_PLAY, SPR2_TWIN|FF_SPR2ENDSTATE, 1, {NULL}, S_PLAY_JUMP, 0, S_PLAY_TWINSPIN}, // S_PLAY_TWINSPIN diff --git a/src/info.h b/src/info.h index a981a39fa..15f25b493 100644 --- a/src/info.h +++ b/src/info.h @@ -609,7 +609,6 @@ enum playersprite SPR2_DEAD, SPR2_DRWN, // drown SPR2_ROLL, - SPR2_SPIN, // spindash charge SPR2_GASP, SPR2_JUMP, SPR2_SPNG, // spring @@ -617,6 +616,8 @@ enum playersprite SPR2_EDGE, SPR2_RIDE, + SPR2_SPIN, // spindash + SPR2_FLY , SPR2_SWIM, SPR2_TIRE, // tired @@ -631,6 +632,9 @@ enum playersprite SPR2_BNCE, // bounce SPR2_BLND, // bounce landing + SPR2_CHRG, // charge + SPR2_FIRE, // fire + SPR2_TWIN, // twinspin SPR2_MLEE, // melee @@ -710,7 +714,6 @@ typedef enum state S_PLAY_DEAD, S_PLAY_DRWN, S_PLAY_ROLL, - S_PLAY_SPINDASH, S_PLAY_GASP, S_PLAY_JUMP, S_PLAY_SPRING, @@ -718,6 +721,9 @@ typedef enum state S_PLAY_EDGE, S_PLAY_RIDE, + // CA2_SPINDASH + S_PLAY_SPINDASH, + // CA_FLY/SWIM S_PLAY_FLY, S_PLAY_SWIM, @@ -736,6 +742,10 @@ typedef enum state S_PLAY_BOUNCE, S_PLAY_BOUNCE_LANDING, + // CA2_GUNSLINGER + S_PLAY_CHARGE, + S_PLAY_FIRE, + // CA_TWINSPIN S_PLAY_TWINSPIN, diff --git a/src/lua_baselib.c b/src/lua_baselib.c index daea8a5c3..ffafb7f34 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1055,11 +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); NOHUD INLEVEL if (!player) return LUA_ErrInvalid(L, "player_t"); - lua_pushboolean(L, P_LookForEnemies(player, nonenemies)); + lua_pushboolean(L, P_LookForEnemies(player, nonenemies, abovehorizontal)); return 1; } diff --git a/src/p_local.h b/src/p_local.h index f50d15870..b7738ed98 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -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 P_LookForEnemies(player_t *player, boolean nonenemies, boolean abovehorizontal); 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); diff --git a/src/p_map.c b/src/p_map.c index e2d296fb4..7ff6301e2 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -938,11 +938,13 @@ static boolean PIT_CheckThing(mobj_t *thing) if (tmthing->eflags & MFE_VERTICALFLIP) { if (thing->z + thing->height <= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) - && thing->z + thing->height + thing->momz >= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz) + && thing->z + thing->height + thing->momz >= tmthing->z + FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz + && !(thing->player->charability == CA_BOUNCE && thing->player->panim == PA_ABILITY && thing->eflags & MFE_VERTICALFLIP)) P_DamageMobj(thing, tmthing, tmthing, 1, 0); } else if (thing->z >= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) - && thing->z + thing->momz <= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz) + && thing->z + thing->momz <= tmthing->z + tmthing->height - FixedMul(FRACUNIT, tmthing->scale) + tmthing->momz + && !(thing->player->charability == CA_BOUNCE && thing->player->panim == PA_ABILITY && !(thing->eflags & MFE_VERTICALFLIP))) P_DamageMobj(thing, tmthing, tmthing, 1, 0); } else if (thing->type == MT_SPIKE && thing->flags & MF_SOLID && tmthing->player) // unfortunate player falls into spike?! @@ -950,11 +952,13 @@ static boolean PIT_CheckThing(mobj_t *thing) if (thing->eflags & MFE_VERTICALFLIP) { if (tmthing->z + tmthing->height <= thing->z - FixedMul(FRACUNIT, thing->scale) - && tmthing->z + tmthing->height + tmthing->momz >= thing->z - FixedMul(FRACUNIT, thing->scale)) + && tmthing->z + tmthing->height + tmthing->momz >= thing->z - FixedMul(FRACUNIT, thing->scale) + && !(tmthing->player->charability == CA_BOUNCE && tmthing->player->panim == PA_ABILITY && tmthing->eflags & MFE_VERTICALFLIP)) P_DamageMobj(tmthing, thing, thing, 1, 0); } else if (tmthing->z >= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) - && tmthing->z + tmthing->momz <= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale)) + && tmthing->z + tmthing->momz <= thing->z + thing->height + FixedMul(FRACUNIT, thing->scale) + && !(tmthing->player->charability == CA_BOUNCE && tmthing->player->panim == PA_ABILITY && !(tmthing->eflags & MFE_VERTICALFLIP))) P_DamageMobj(tmthing, thing, thing, 1, 0); } diff --git a/src/p_mobj.c b/src/p_mobj.c index 4de36ff07..5a3651a54 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -280,6 +280,10 @@ 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; @@ -470,6 +474,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_MELEE: case S_PLAY_MELEE_FINISH: case S_PLAY_MELEE_LANDING: @@ -517,7 +523,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) else mobj->tics = 1; } - else if (player->panim == PA_ABILITY2 && player->charability2 == CA2_SPINDASH) + else if (player->panim == PA_ABILITY2 && (player->charability2 == CA2_SPINDASH || state == S_PLAY_CHARGE)) { fixed_t step = (player->maxdash - player->mindash)/4; speed = (player->dashspeed - player->mindash); diff --git a/src/p_user.c b/src/p_user.c index 59142edd0..3b505651b 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -3775,10 +3775,9 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) { player->mo->momx = player->cmomx; player->mo->momy = player->cmomy; - player->pflags |= PF_STARTDASH|PF_SPINNING; + player->pflags |= (PF_USEDOWN|PF_STARTDASH|PF_SPINNING); player->dashspeed = player->mindash; P_SetPlayerMobjState(player->mo, S_PLAY_SPINDASH); - player->pflags |= PF_USEDOWN; if (!player->spectator) S_StartSound(player->mo, sfx_s3kab); // Make the rev sound! Previously sfx_spndsh. } @@ -3809,15 +3808,97 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) && !player->climbing && !player->mo->momz && onground && (player->speed > FixedMul(5<mo->scale) || !canstand) && !(player->pflags & (PF_USEDOWN|PF_SPINNING))) { - player->pflags |= PF_SPINNING; + player->pflags |= (PF_USEDOWN|PF_SPINNING); P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); if (!player->spectator) S_StartSound(player->mo, sfx_spin); - player->pflags |= PF_USEDOWN; + } + else + // Catapult the player from a spindash rev! + if (onground && !(player->pflags & PF_USEDOWN) && (player->pflags & PF_STARTDASH) && (player->pflags & PF_SPINNING)) + { + player->pflags &= ~PF_STARTDASH; + if (player->powers[pw_carry] == CR_BRAKGOOP) + player->dashspeed = 0; + + if (!((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE)) + { + if (player->dashspeed) + { + P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); + P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->dashspeed, player->mo->scale)); // catapult forward ho!! + } + else + { + P_SetPlayerMobjState(player->mo, S_PLAY_STND); + player->pflags &= ~PF_SPINNING; + } + + if (!player->spectator) + S_StartSound(player->mo, sfx_zoom); + } + + player->dashspeed = 0; + } + break; + case CA2_GUNSLINGER: + if ((cmd->buttons & BT_USE) + && !player->mo->momz && onground + && 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); + + P_SetPlayerMobjState(player->mo, S_PLAY_FIRE); + + if (maxspeed && 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); + } + 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))) + { + cork->flags &= ~MF_NOGRAVITY; + if (!maxspeed) + cork->flags |= MF_NOCLIPTHING; + } + } + 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)); + } + P_SetTarget(&player->mo->tracer, NULL); + player->dashspeed = 0; } break; case CA2_MELEE: // Melee attack - if (!(player->panim == PA_ABILITY2) && (cmd->buttons & BT_USE) + if (player->panim != PA_ABILITY2 && (cmd->buttons & BT_USE) && !player->mo->momz && onground && !(player->pflags & PF_USEDOWN) && canstand) { @@ -3870,33 +3951,6 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) } } - // Catapult the player from a spindash rev! - if (onground && !(player->pflags & PF_USEDOWN) && (player->pflags & PF_STARTDASH) && (player->pflags & PF_SPINNING)) - { - player->pflags &= ~PF_STARTDASH; - if (player->powers[pw_carry] == CR_BRAKGOOP) - player->dashspeed = 0; - - if (!((gametype == GT_RACE || gametype == GT_COMPETITION) && leveltime < 4*TICRATE)) - { - if (player->dashspeed) - { - P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); - P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->dashspeed, player->mo->scale)); // catapult forward ho!! - } - else - { - P_SetPlayerMobjState(player->mo, S_PLAY_STND); - player->pflags &= ~PF_SPINNING; - } - - if (!player->spectator) - S_StartSound(player->mo, sfx_zoom); - } - - player->dashspeed = 0; - } - if (onground && player->pflags & PF_STARTDASH) { if (player->mo->state-states != S_PLAY_SPINDASH) @@ -4211,7 +4265,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) if (player->charability == CA_HOMINGTHOK && !player->homing) { - if (P_LookForEnemies(player, true)) + if (P_LookForEnemies(player, true, false)) { if (player->mo->tracer) player->homing = 3*TICRATE; @@ -4885,13 +4939,14 @@ static void P_3dMovement(player_t *player) // Allow a bit of movement while spinning if (player->pflags & PF_SPINNING) { - if ((mforward && cmd->forwardmove > 0) || (mbackward && cmd->forwardmove < 0)) + if ((mforward && cmd->forwardmove > 0) || (mbackward && cmd->forwardmove < 0) + || (player->pflags & PF_STARTDASH)) movepushforward = 0; - else if (!(player->pflags & PF_STARTDASH)) - movepushforward = FixedDiv(movepushforward, 16*FRACUNIT); else - movepushforward = 0; + movepushforward = FixedDiv(movepushforward, 16*FRACUNIT); } + else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2) + movepushforward = 0; movepushforward = FixedMul(movepushforward, player->mo->scale); @@ -4928,13 +4983,14 @@ static void P_3dMovement(player_t *player) { // Stupid little movement prohibitor hack // that REALLY shouldn't belong in analog code. - if ((mforward && cmd->forwardmove > 0) || (mbackward && cmd->forwardmove < 0)) + if ((mforward && cmd->forwardmove > 0) || (mbackward && cmd->forwardmove < 0) + || (player->pflags & PF_STARTDASH)) movepushforward = 0; - else if (!(player->pflags & PF_STARTDASH)) - movepushforward = FixedDiv(movepushforward, 16*FRACUNIT); else - movepushforward = 0; + movepushforward = FixedDiv(movepushforward, 16*FRACUNIT); } + else if (player->charability2 == CA2_GUNSLINGER && player->panim == PA_ABILITY2) + movepushforward = 0; movepushsideangle = controldirection; @@ -4964,11 +5020,13 @@ static void P_3dMovement(player_t *player) // Allow a bit of movement while spinning if (player->pflags & PF_SPINNING) { - if (!(player->pflags & PF_STARTDASH)) - movepushside = FixedDiv(movepushside,16*FRACUNIT); - else + if ((player->pflags & PF_STARTDASH)) movepushside = 0; + 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); @@ -6555,6 +6613,7 @@ 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->pflags |= PF_FULLSTASIS; else if (player->powers[pw_nocontrol]) @@ -7165,7 +7224,7 @@ static void P_MovePlayer(player_t *player) case SH_ATTRACT: player->pflags |= PF_THOKKED|PF_SHIELDABILITY; player->homing = 2; - if (P_LookForEnemies(player, false) && player->mo->tracer) + if (P_LookForEnemies(player, false, false) && player->mo->tracer) { player->pflags &= ~PF_NOJUMPDAMAGE; P_SetPlayerMobjState(player->mo, S_PLAY_ROLL); @@ -7812,8 +7871,9 @@ 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. // -boolean P_LookForEnemies(player_t *player, boolean nonenemies) +boolean P_LookForEnemies(player_t *player, boolean nonenemies, boolean abovehorizontal) { mobj_t *mo; thinker_t *think; @@ -7845,13 +7905,30 @@ boolean P_LookForEnemies(player_t *player, boolean nonenemies) if (mo->type == MT_DETON) // Don't be STUPID, Sonic! continue; - if (((mo->z > player->mo->z+FixedMul(MAXSTEPMOVE, player->mo->scale)) && !(player->mo->eflags & MFE_VERTICALFLIP)) - || ((mo->z+mo->height < player->mo->z+player->mo->height-FixedMul(MAXSTEPMOVE, player->mo->scale)) && (player->mo->eflags & MFE_VERTICALFLIP))) // Reverse gravity check - Flame. - continue; // Don't home upwards! + { + fixed_t dist = P_AproxDistance(player->mo->x-mo->x, player->mo->y-mo->y); - if (P_AproxDistance(P_AproxDistance(player->mo->x-mo->x, player->mo->y-mo->y), - player->mo->z-mo->z) > FixedMul(RING_DIST, player->mo->scale)) - continue; // out of range + if (abovehorizontal) + { + angle_t ang = R_PointToAngle2(0, player->mo->z, dist, mo->z) + ANGLE_45; + if (ang > ANGLE_90) + continue; // Don't home outside of desired angle! + } + else // Don't home upwards! + { + if (player->mo->eflags & MFE_VERTICALFLIP) + { + if (mo->z > player->mo->z+FixedMul(MAXSTEPMOVE, player->mo->scale)) + continue; + } + else if (mo->z+mo->height < player->mo->z+player->mo->height-FixedMul(MAXSTEPMOVE, player->mo->scale)) + continue; + } + + if (P_AproxDistance(dist, + player->mo->z-mo->z) > FixedMul(RING_DIST, player->mo->scale)) + continue; // out of range + } if ((twodlevel || player->mo->flags2 & MF2_TWOD) && abs(player->mo->y-mo->y) > player->mo->radius)