diff --git a/src/info.c b/src/info.c index 47d593aac..3faf15dd0 100644 --- a/src/info.c +++ b/src/info.c @@ -28994,7 +28994,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_SPECIAL_UFO -1, // doomednum S_CHAOSEMERALD1, // spawnstate - 1000, // spawnhealth + 101, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime diff --git a/src/k_kart.c b/src/k_kart.c index 2505d7ea8..ca030f88a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7666,12 +7666,18 @@ static void K_MoveHeldObjects(player_t *player) } } -player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) +mobj_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) { fixed_t best = INT32_MAX; - player_t *wtarg = NULL; + mobj_t *wtarg = NULL; INT32 i; + if (specialStage.active == true) + { + // Always target the UFO. + return specialStage.ufo; + } + for (i = 0; i < MAXPLAYERS; i++) { angle_t thisang = ANGLE_MAX; @@ -7687,7 +7693,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) player = &players[i]; // Don't target yourself, stupid. - if (player == source) + if (source != NULL && player == source) { continue; } @@ -7726,7 +7732,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) if (gametyperules & GTR_CIRCUIT) { - if (player->position >= source->position) + if (source != NULL && player->position >= source->position) { // Don't pay attention to people who aren't above your position continue; @@ -7768,7 +7774,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) if (thisScore < best) { - wtarg = player; + wtarg = player->mo; best = thisScore; } } @@ -8877,24 +8883,32 @@ void K_KartPlayerAfterThink(player_t *player) // Jawz reticule (seeking) if (player->itemtype == KITEM_JAWZ && (player->pflags & PF_ITEMOUT)) { - INT32 lastTargID = player->lastjawztarget; - player_t *lastTarg = NULL; - player_t *targ = NULL; + const INT32 lastTargID = player->lastjawztarget; + mobj_t *lastTarg = NULL; + + INT32 targID = MAXPLAYERS; + mobj_t *targ = NULL; + mobj_t *ret = NULL; - if ((lastTargID >= 0 && lastTargID <= MAXPLAYERS) + if (specialStage.active == true && lastTargID == MAXPLAYERS) + { + // Aiming at the UFO. + lastTarg = specialStage.ufo; + } + else if ((lastTargID >= 0 && lastTargID <= MAXPLAYERS) && playeringame[lastTargID] == true) { if (players[lastTargID].spectator == false) { - lastTarg = &players[lastTargID]; + lastTarg = players[lastTargID].mo; } } if (player->throwdir == -1) { // Backwards Jawz targets yourself. - targ = player; + targ = player->mo; player->jawztargetdelay = 0; } else @@ -8903,9 +8917,14 @@ void K_KartPlayerAfterThink(player_t *player) targ = K_FindJawzTarget(player->mo, player, ANGLE_45); } - if (targ != NULL && targ->mo != NULL && P_MobjWasRemoved(targ->mo) == false) + if (targ != NULL && P_MobjWasRemoved(targ) == false) { - if (targ - players == lastTargID) + if (targ->player != NULL) + { + targID = targ->player - players; + } + + if (targID == lastTargID) { // Increment delay. if (player->jawztargetdelay < 10) @@ -8924,33 +8943,33 @@ void K_KartPlayerAfterThink(player_t *player) else { // Allow a swap. - if (P_IsDisplayPlayer(player) || P_IsDisplayPlayer(targ)) + if (P_IsDisplayPlayer(player) || P_IsDisplayPlayer(targ->player)) { S_StartSound(NULL, sfx_s3k89); } else { - S_StartSound(targ->mo, sfx_s3k89); + S_StartSound(targ, sfx_s3k89); } - player->lastjawztarget = targ - players; + player->lastjawztarget = targID; player->jawztargetdelay = 5; } } } - if (targ == NULL || targ->mo == NULL || P_MobjWasRemoved(targ->mo) == true) + if (targ == NULL || P_MobjWasRemoved(targ) == true) { player->lastjawztarget = -1; player->jawztargetdelay = 0; return; } - ret = P_SpawnMobj(targ->mo->x, targ->mo->y, targ->mo->z, MT_PLAYERRETICULE); - ret->old_x = targ->mo->old_x; - ret->old_y = targ->mo->old_y; - ret->old_z = targ->mo->old_z; - P_SetTarget(&ret->target, targ->mo); + ret = P_SpawnMobj(targ->x, targ->y, targ->z, MT_PLAYERRETICULE); + ret->old_x = targ->old_x; + ret->old_y = targ->old_y; + ret->old_z = targ->old_z; + P_SetTarget(&ret->target, targ); ret->frame |= ((leveltime % 10) / 2); ret->tics = 1; ret->color = player->skincolor; diff --git a/src/k_kart.h b/src/k_kart.h index b12da338e..8f43a6f37 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -123,7 +123,7 @@ void K_UpdateHnextList(player_t *player, boolean clean); void K_DropHnextList(player_t *player, boolean keepshields); void K_RepairOrbitChain(mobj_t *orbit); void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player); -player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range); +mobj_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range); INT32 K_GetKartRingPower(player_t *player, boolean boosted); void K_UpdateDistanceFromFinishLine(player_t *const player); boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y); diff --git a/src/k_objects.h b/src/k_objects.h index 7564fcc20..a8daaf50b 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -56,6 +56,7 @@ void Obj_DuelBombInit(mobj_t *bomb); /* Special Stage UFO */ void Obj_SpecialUFOThinker(mobj_t *bomb); +boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType); mobj_t *Obj_CreateSpecialUFO(void); UINT32 K_GetSpecialUFODistance(void); diff --git a/src/objects/jawz.c b/src/objects/jawz.c index cc241ba87..52a52a95c 100644 --- a/src/objects/jawz.c +++ b/src/objects/jawz.c @@ -140,17 +140,21 @@ static void JawzChase(mobj_t *th, boolean grounded) if (jawz_chase(th) == NULL || P_MobjWasRemoved(jawz_chase(th)) == true) { + mobj_t *newChase = NULL; + player_t *owner = NULL; + th->angle = K_MomentumAngle(th); - if (jawz_owner(th) != NULL && P_MobjWasRemoved(jawz_owner(th)) == false - && jawz_owner(th)->player != NULL) + if ((jawz_owner(th) != NULL && P_MobjWasRemoved(jawz_owner(th)) == false) + && (jawz_owner(th)->player != NULL)) { - player_t *newPlayer = K_FindJawzTarget(th, jawz_owner(th)->player, ANGLE_90); + owner = jawz_owner(th)->player; + } - if (newPlayer != NULL) - { - P_SetTarget(&jawz_chase(th), newPlayer->mo); - } + newChase = K_FindJawzTarget(th, owner, ANGLE_90); + if (newChase != NULL) + { + P_SetTarget(&jawz_chase(th), newChase); } } diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 3d2ad68d7..fa26ef51d 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -7,8 +7,8 @@ // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file shrink.c -/// \brief Shrink laser item code. +/// \file ufo.c +/// \brief Special Stage UFO #include "../doomdef.h" #include "../doomstat.h" @@ -24,11 +24,11 @@ #include "../k_waypoint.h" #include "../k_specialstage.h" -#define UFO_BASE_SPEED (12 * FRACUNIT) // UFO's slowest speed. -#define UFO_SPEEDUP (FRACUNIT) +#define UFO_BASE_SPEED (16 * FRACUNIT) // UFO's slowest speed. +#define UFO_SPEEDUP (FRACUNIT >> 3) #define UFO_SLOWDOWN (FRACUNIT >> 2) #define UFO_SPACING (1024 * FRACUNIT) -#define UFO_DEADZONE (512 * FRACUNIT) +#define UFO_DEADZONE (768 * FRACUNIT) #define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10) #define ufo_waypoint(o) ((o)->extravalue1) @@ -49,6 +49,11 @@ static fixed_t GenericDistance( return P_AproxDistance(P_AproxDistance(destx - curx, desty - cury), destz - curz); } +static boolean UFOEmeraldChase(mobj_t *ufo) +{ + return (ufo->health <= 1); +} + static void UFOUpdateDistanceToFinish(mobj_t *ufo) { waypoint_t *finishLine = K_GetFinishLineWaypoint(); @@ -314,17 +319,86 @@ static void UFOMove(mobj_t *ufo) } } +static void UFOEmeraldVFX(mobj_t *ufo) +{ + if (leveltime % 3 == 0) + { + mobj_t *sparkle = P_SpawnMobjFromMobj( + ufo, + P_RandomRange(PR_SPARKLE, -48, 48) * FRACUNIT, + P_RandomRange(PR_SPARKLE, -48, 48) * FRACUNIT, + P_RandomRange(PR_SPARKLE, 0, 64) * FRACUNIT, + MT_EMERALDSPARK + ); + + sparkle->color = ufo->color; + sparkle->momz += 8 * ufo->scale * P_MobjFlip(ufo); + } +} + void Obj_SpecialUFOThinker(mobj_t *ufo) { UFOMove(ufo); UFOUpdateAngle(ufo); UFOUpdateDistanceToFinish(ufo); UFOUpdateSpeed(ufo); + + if (UFOEmeraldChase(ufo) == true) + { + // Spawn emerald sparkles + UFOEmeraldVFX(ufo); + } +} + +static UINT8 GetUFODamage(mobj_t *inflictor) +{ + if (inflictor == NULL || P_MobjWasRemoved(inflictor) == true) + { + return 1; + } + + switch (inflictor->type) + { + default: + { + return 1; + } + } +} + +boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType) +{ + UINT8 damage = 1; + + (void)source; + (void)damageType; + + if (UFOEmeraldChase(ufo) == true) + { + // Damaged fully already, no need for any more. + ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW); // Double check flags, just to be sure. + return false; + } + + damage = GetUFODamage(inflictor); + + if (damage >= ufo->health - 1) + { + // Turn into just an emerald, and make it collectible! + ufo->health = 1; + ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW); + return true; + } + + ufo->health -= damage; + K_SetHitLagForObjects(ufo, inflictor, damage * 6, true); + return true; } static mobj_t *InitSpecialUFO(waypoint_t *start) { mobj_t *ufo = NULL; + mobj_t *underlay = NULL; if (start == NULL) { @@ -343,6 +417,13 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) ufo_speed(ufo) = UFO_BASE_SPEED; + ufo->color = SKINCOLOR_CHAOSEMERALD1; + + underlay = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&underlay->target, ufo); + P_SetMobjState(underlay, S_CHAOSEMERALD_UNDER); + underlay->color = ufo->color; + return ufo; } diff --git a/src/p_inter.c b/src/p_inter.c index e77a5d8ff..c18a151aa 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2222,6 +2222,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } else { + if (target->type == MT_SPECIAL_UFO) + { + return Obj_SpecialUFODamage(target, inflictor, source, damagetype); + } + if (damagetype & DMG_STEAL) { // Not a player, steal damage is intended to not do anything