From 9d350c64c81d23754346ce3e254a8d872c059759 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 19 Dec 2022 04:49:53 -0500 Subject: [PATCH] Allow SPB to attack the UFO properly --- src/info.c | 2 +- src/k_objects.h | 1 + src/objects/spb.c | 181 +++++++++++++++++++++++++++++----------------- src/objects/ufo.c | 112 ++++++++++++++++++++-------- src/p_inter.c | 5 -- src/p_map.c | 47 ++++++++++++ 6 files changed, 243 insertions(+), 105 deletions(-) diff --git a/src/info.c b/src/info.c index 23d2a31c9..4566222f3 100644 --- a/src/info.c +++ b/src/info.c @@ -23631,7 +23631,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_kc64, // activesound - MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + MF_SOLID|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, diff --git a/src/k_objects.h b/src/k_objects.h index c0da8034f..284ec1c61 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -59,6 +59,7 @@ mobj_t *Obj_SpawnBrolyKi(mobj_t *source, tic_t duration); void Obj_BrolyKiThink(mobj_t *ki); /* Special Stage UFO */ +waypoint_t *K_GetSpecialUFOWaypoint(mobj_t *ufo); void Obj_SpecialUFOThinker(mobj_t *ufo); boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType); void Obj_PlayerUFOCollide(mobj_t *ufo, mobj_t *other); diff --git a/src/objects/spb.c b/src/objects/spb.c index 32cb0e12d..b76dfd4f8 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -23,6 +23,7 @@ #include "../z_zone.h" #include "../k_waypoint.h" #include "../k_respawn.h" +#include "../k_specialstage.h" #define SPB_SLIPTIDEDELTA (ANG1 * 3) #define SPB_STEERDELTA (ANGLE_90 - ANG10) @@ -292,7 +293,7 @@ static boolean SPBSeekSoundPlaying(mobj_t *spb) || S_SoundPlaying(spb, sfx_spbskc)); } -static void SPBSeek(mobj_t *spb, player_t *bestPlayer) +static void SPBSeek(mobj_t *spb, mobj_t *bestMobj) { const fixed_t desiredSpeed = SPB_DEFAULTSPEED; @@ -321,16 +322,15 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) spb_lastplayer(spb) = -1; // Just make sure this is reset - if (bestPlayer == NULL - || bestPlayer->mo == NULL - || P_MobjWasRemoved(bestPlayer->mo) == true - || bestPlayer->mo->health <= 0 - || (bestPlayer->respawn.state != RESPAWNST_NONE)) + if (bestMobj == NULL + || P_MobjWasRemoved(bestMobj) == true + || bestMobj->health <= 0 + || (bestMobj->player != NULL && bestMobj->player->respawn.state != RESPAWNST_NONE)) { // No one there? Completely STOP. spb->momx = spb->momy = spb->momz = 0; - if (bestPlayer == NULL) + if (bestMobj == NULL) { spbplace = -1; } @@ -339,8 +339,16 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) } // Found someone, now get close enough to initiate the slaughter... - P_SetTarget(&spb_chase(spb), bestPlayer->mo); - spbplace = bestPlayer->position; + P_SetTarget(&spb_chase(spb), bestMobj); + + if (bestMobj->player != NULL) + { + spbplace = bestMobj->player->position; + } + else + { + spbplace = 1; + } dist = SPBDist(spb, spb_chase(spb)); activeDist = FixedMul(SPB_ACTIVEDIST, spb_chase(spb)->scale); @@ -400,7 +408,18 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) curWaypoint = K_GetWaypointFromIndex( (size_t)spb_curwaypoint(spb) ); } - destWaypoint = bestPlayer->nextwaypoint; + if (bestMobj->player != NULL) + { + destWaypoint = bestMobj->player->nextwaypoint; + } + else if (bestMobj->type == MT_SPECIAL_UFO) + { + destWaypoint = K_GetSpecialUFOWaypoint(bestMobj); + } + else + { + destWaypoint = K_GetBestWaypointForMobj(bestMobj); + } if (curWaypoint != NULL) { @@ -433,7 +452,8 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) if (pathfindsuccess == true) { - if (cv_spbtest.value) { + if (cv_spbtest.value) + { if (pathtoplayer.numnodes > 1) { // Go to the next waypoint. @@ -529,45 +549,48 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) SetSPBSpeed(spb, xySpeed, zSpeed); - // see if a player is near us, if they are, try to hit them by slightly thrusting towards them, otherwise, bleh! - steerDist = 1536 * mapobjectscale; - - for (i = 0; i < MAXPLAYERS; i++) + if (specialStage.active == false) { - fixed_t ourDist = INT32_MAX; - INT32 ourDelta = INT32_MAX; + // see if a player is near us, if they are, try to hit them by slightly thrusting towards them, otherwise, bleh! + steerDist = 1536 * mapobjectscale; - if (playeringame[i] == false || players[i].spectator == true) + for (i = 0; i < MAXPLAYERS; i++) { - // Not in-game - continue; + fixed_t ourDist = INT32_MAX; + INT32 ourDelta = INT32_MAX; + + if (playeringame[i] == false || players[i].spectator == true) + { + // Not in-game + continue; + } + + if (players[i].mo == NULL || P_MobjWasRemoved(players[i].mo) == true) + { + // Invalid mobj + continue; + } + + ourDelta = AngleDelta(spb->angle, R_PointToAngle2(spb->x, spb->y, players[i].mo->x, players[i].mo->y)); + if (ourDelta > SPB_STEERDELTA) + { + // Check if the angle wouldn't make us LOSE speed. + continue; + } + + ourDist = R_PointToDist2(spb->x, spb->y, players[i].mo->x, players[i].mo->y); + if (ourDist < steerDist) + { + steerDist = ourDist; + steerMobj = players[i].mo; // it doesn't matter if we override this guy now. + } } - if (players[i].mo == NULL || P_MobjWasRemoved(players[i].mo) == true) + // different player from our main target, try and ram into em~! + if (steerMobj != NULL && steerMobj != spb_chase(spb)) { - // Invalid mobj - continue; + P_Thrust(spb, R_PointToAngle2(spb->x, spb->y, steerMobj->x, steerMobj->y), spb_speed(spb) / 4); } - - ourDelta = AngleDelta(spb->angle, R_PointToAngle2(spb->x, spb->y, players[i].mo->x, players[i].mo->y)); - if (ourDelta > SPB_STEERDELTA) - { - // Check if the angle wouldn't make us LOSE speed. - continue; - } - - ourDist = R_PointToDist2(spb->x, spb->y, players[i].mo->x, players[i].mo->y); - if (ourDist < steerDist) - { - steerDist = ourDist; - steerMobj = players[i].mo; // it doesn't matter if we override this guy now. - } - } - - // different player from our main target, try and ram into em~! - if (steerMobj != NULL && steerMobj != spb_chase(spb)) - { - P_Thrust(spb, R_PointToAngle2(spb->x, spb->y, steerMobj->x, steerMobj->y), spb_speed(spb) / 4); } if (sliptide != 0) @@ -593,7 +616,7 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) } } -static void SPBChase(mobj_t *spb, player_t *bestPlayer) +static void SPBChase(mobj_t *spb, mobj_t *bestMobj) { fixed_t baseSpeed = 0; fixed_t maxSpeed = 0; @@ -642,8 +665,8 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer) S_StartSound(spb, spb->info->activesound); } - // Maybe we want SPB to target an object later? IDK lol chasePlayer = chase->player; + if (chasePlayer != NULL) { UINT8 fracmax = 32; @@ -679,7 +702,8 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer) cy = chasePlayer->cmomy; // Switch targets if you're no longer 1st for long enough - if (bestPlayer != NULL && chasePlayer->position <= bestPlayer->position) + if (bestMobj != NULL + && (bestMobj->player == NULL || chasePlayer->position <= bestMobj->player->position)) { spb_modetimer(spb) = SPB_HOTPOTATO; } @@ -697,6 +721,12 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer) } } } + else + { + spb_lastplayer(spb) = -1; + spbplace = 1; + spb_modetimer(spb) = SPB_HOTPOTATO; + } dist = P_AproxDistance(P_AproxDistance(spb->x - chase->x, spb->y - chase->y), spb->z - chase->z); @@ -807,7 +837,7 @@ static void SPBWait(mobj_t *spb) void Obj_SPBThink(mobj_t *spb) { mobj_t *ghost = NULL; - player_t *bestPlayer = NULL; + mobj_t *bestMobj = NULL; UINT8 bestRank = UINT8_MAX; size_t i; @@ -844,6 +874,15 @@ void Obj_SPBThink(mobj_t *spb) } else { + if (specialStage.active == true) + { + if (specialStage.ufo != NULL && P_MobjWasRemoved(specialStage.ufo) == false) + { + bestRank = 1; + bestMobj = specialStage.ufo; + } + } + // Find the player with the best rank for (i = 0; i < MAXPLAYERS; i++) { @@ -886,7 +925,7 @@ void Obj_SPBThink(mobj_t *spb) if (player->position < bestRank) { bestRank = player->position; - bestPlayer = player; + bestMobj = player->mo; } } @@ -894,11 +933,11 @@ void Obj_SPBThink(mobj_t *spb) { case SPB_MODE_SEEK: default: - SPBSeek(spb, bestPlayer); + SPBSeek(spb, bestMobj); break; case SPB_MODE_CHASE: - SPBChase(spb, bestPlayer); + SPBChase(spb, bestMobj); break; case SPB_MODE_WAIT: @@ -970,14 +1009,18 @@ void Obj_SPBExplode(mobj_t *spb) void Obj_SPBTouch(mobj_t *spb, mobj_t *toucher) { - player_t *player = toucher->player; + player_t *const player = toucher->player; + mobj_t *owner = NULL; + mobj_t *chase = NULL; if (spb_intangible(spb) > 0) { return; } - if ((spb_owner(spb) == toucher || spb_owner(spb) == toucher->target) + owner = spb_owner(spb); + + if ((owner == toucher || owner == toucher->target) && (spb_nothink(spb) > 0)) { return; @@ -988,30 +1031,34 @@ void Obj_SPBTouch(mobj_t *spb, mobj_t *toucher) return; } - if (player->spectator == true) + if (player != NULL) { - return; + if (player->spectator == true) + { + return; + } + + if (player->bubbleblowup > 0) + { + // Stun the SPB, and remove the shield. + K_DropHnextList(player, false); + spb_mode(spb) = SPB_MODE_WAIT; + spb_modetimer(spb) = 55; // Slightly over the respawn timer length + return; + } } - if (player->bubbleblowup > 0) - { - // Stun the SPB, and remove the shield. - K_DropHnextList(player, false); - spb_mode(spb) = SPB_MODE_WAIT; - spb_modetimer(spb) = 55; // Slightly over the respawn timer length - return; - } - - if (spb_chase(spb) != NULL && P_MobjWasRemoved(spb_chase(spb)) == false - && toucher == spb_chase(spb)) + chase = spb_chase(spb); + if (chase != NULL && P_MobjWasRemoved(chase) == false + && toucher == chase) { // Cause the explosion. Obj_SPBExplode(spb); return; } - else + else if (toucher->flags & MF_SHOOTABLE) { // Regular spinout, please. - P_DamageMobj(toucher, spb, spb_owner(spb), 1, DMG_NORMAL); + P_DamageMobj(toucher, spb, owner, 1, DMG_NORMAL); } } diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 303b0bc9d..96b2be1db 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -237,6 +237,25 @@ static void UFOUpdateAngle(mobj_t *ufo) ufo->angle += delta >> 2; } +waypoint_t *K_GetSpecialUFOWaypoint(mobj_t *ufo) +{ + if ((ufo == NULL) && (specialStage.active == true)) + { + ufo = specialStage.ufo; + } + + if (ufo != NULL && P_MobjWasRemoved(ufo) == false + && ufo->type == MT_SPECIAL_UFO) + { + if (ufo_waypoint(ufo) >= 0) + { + return K_GetWaypointFromIndex((size_t)ufo_waypoint(ufo)); + } + } + + return NULL; +} + static void UFOMove(mobj_t *ufo) { waypoint_t *curWaypoint = NULL; @@ -256,11 +275,7 @@ static void UFOMove(mobj_t *ufo) boolean reachedEnd = false; - if (ufo_waypoint(ufo) >= 0) - { - curWaypoint = K_GetWaypointFromIndex((size_t)ufo_waypoint(ufo)); - } - + curWaypoint = K_GetSpecialUFOWaypoint(ufo); destWaypoint = K_GetFinishLineWaypoint(); if (curWaypoint == NULL || destWaypoint == NULL) @@ -466,40 +481,74 @@ static void UFOKillPieces(mobj_t *ufo) } } -static UINT8 GetUFODamage(mobj_t *inflictor) +static UINT8 GetUFODamage(mobj_t *inflictor, UINT8 damageType) { - if (inflictor == NULL || P_MobjWasRemoved(inflictor) == true) + if (inflictor != NULL && P_MobjWasRemoved(inflictor) == false) { - // Default damage value. - return 10; + switch (inflictor->type) + { + case MT_JAWZ: + case MT_JAWZ_SHIELD: + case MT_ORBINAUT_SHIELD: + { + // Jawz / shields deal regular damage. + return 10; + } + case MT_ORBINAUT: + { + // Thrown orbinauts deal double damage. + return 20; + } + case MT_SPB: + { + // SPB deals triple damage. + return 30; + } + case MT_BANANA: + { + // Banana snipes deal triple damage, + // laid down bananas deal regular damage. + if (inflictor->health > 1) + { + return 30; + } + + return 10; + } + case MT_PLAYER: + { + // Players deal damage relative to how many sneakers they used. + return 15 * max(1, inflictor->player->numsneakers); + } + default: + { + break; + } + } } - switch (inflictor->type) + // Guess from damage type. + switch (damageType & DMG_TYPEMASK) { - case MT_SPB: - case MT_BANANA: - { - // SPB deals triple damage. - return 30; - } - case MT_PLAYER: - { - // Players deal damage relative to how many sneakers they used. - return 15 * inflictor->player->numsneakers; - } - case MT_ORBINAUT: - { - // Thrown orbinauts deal double damage. - return 20; - } - case MT_JAWZ: - case MT_JAWZ_SHIELD: - case MT_ORBINAUT_SHIELD: + case DMG_NORMAL: + case DMG_STING: default: { - // Jawz / shields deal regular damage. return 10; } + case DMG_WIPEOUT: + { + return 20; + } + case DMG_EXPLODE: + case DMG_TUMBLE: + { + return 30; + } + case DMG_VOLTAGE: + { + return 15; + } } } @@ -509,7 +558,6 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN UINT8 damage = 1; (void)source; - (void)damageType; if (UFOEmeraldChase(ufo) == true) { @@ -517,7 +565,7 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN return false; } - damage = GetUFODamage(inflictor); + damage = GetUFODamage(inflictor, damageType); if (damage <= 0) { diff --git a/src/p_inter.c b/src/p_inter.c index de1d0ef25..ca6612308 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -352,11 +352,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->target->player->karmadelay = comebacktime; } return; - case MT_SPB: - { - Obj_SPBTouch(special, toucher); - return; - } case MT_DUELBOMB: { Obj_DuelBombTouch(special, toucher); diff --git a/src/p_map.c b/src/p_map.c index 35d4bc431..04978c483 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -751,6 +751,53 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // SRB2kart 011617 - Colission[sic] code for kart items //{ + if (thing->type == MT_SPB) + { + if (tm.thing->type != MT_PLAYER + && thing->tracer != tm.thing) + { + // Needs to be a player or the + // thing that we're chasing. + return BMIT_CONTINUE; + } + + if (tm.thing->z > thing->z + thing->height) + { + return BMIT_CONTINUE; // overhead + } + + if (tm.thing->z + tm.thing->height < thing->z) + { + return BMIT_CONTINUE; // underneath + } + + Obj_SPBTouch(thing, tm.thing); + return BMIT_CONTINUE; + } + else if (tm.thing->type == MT_SPB) + { + if (thing->type != MT_PLAYER + && tm.thing->tracer != thing) + { + // Needs to be a player or the + // thing that we're chasing. + return BMIT_CONTINUE; + } + + if (tm.thing->z > thing->z + thing->height) + { + return BMIT_CONTINUE; // overhead + } + + if (tm.thing->z + tm.thing->height < thing->z) + { + return BMIT_CONTINUE; // underneath + } + + Obj_SPBTouch(tm.thing, thing); + return BMIT_CONTINUE; + } + if (thing->type == MT_SHRINK_GUN || thing->type == MT_SHRINK_PARTICLE) { if (tm.thing->type != MT_PLAYER)