Lots more UFO work

- UFO is able to be damaged. (No damage values set yet, so it has an obnoxious amount of health.)
- Emerald becomes collectible when fully damaged.
- Jawz can target the UFO.
- Tweaked some of the speed values.
This commit is contained in:
Sally Coolatta 2022-11-22 16:31:30 -05:00
parent dc6caf1eb3
commit d1b2e42560
7 changed files with 146 additions and 36 deletions

View file

@ -29061,7 +29061,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
{ // MT_SPECIAL_UFO { // MT_SPECIAL_UFO
-1, // doomednum -1, // doomednum
S_CHAOSEMERALD1, // spawnstate S_CHAOSEMERALD1, // spawnstate
1000, // spawnhealth 101, // spawnhealth
S_NULL, // seestate S_NULL, // seestate
sfx_None, // seesound sfx_None, // seesound
8, // reactiontime 8, // reactiontime

View file

@ -6716,12 +6716,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; fixed_t best = INT32_MAX;
player_t *wtarg = NULL; mobj_t *wtarg = NULL;
INT32 i; INT32 i;
if (specialStage.active == true)
{
// Always target the UFO.
return specialStage.ufo;
}
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
angle_t thisang = ANGLE_MAX; angle_t thisang = ANGLE_MAX;
@ -6737,7 +6743,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range)
player = &players[i]; player = &players[i];
// Don't target yourself, stupid. // Don't target yourself, stupid.
if (player == source) if (source != NULL && player == source)
{ {
continue; continue;
} }
@ -6776,7 +6782,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range)
if (gametyperules & GTR_CIRCUIT) 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 // Don't pay attention to people who aren't above your position
continue; continue;
@ -6818,7 +6824,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range)
if (thisScore < best) if (thisScore < best)
{ {
wtarg = player; wtarg = player->mo;
best = thisScore; best = thisScore;
} }
} }
@ -7944,24 +7950,32 @@ void K_KartPlayerAfterThink(player_t *player)
// Jawz reticule (seeking) // Jawz reticule (seeking)
if (player->itemtype == KITEM_JAWZ && (player->pflags & PF_ITEMOUT)) if (player->itemtype == KITEM_JAWZ && (player->pflags & PF_ITEMOUT))
{ {
INT32 lastTargID = player->lastjawztarget; const INT32 lastTargID = player->lastjawztarget;
player_t *lastTarg = NULL; mobj_t *lastTarg = NULL;
player_t *targ = NULL;
INT32 targID = MAXPLAYERS;
mobj_t *targ = NULL;
mobj_t *ret = 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) && playeringame[lastTargID] == true)
{ {
if (players[lastTargID].spectator == false) if (players[lastTargID].spectator == false)
{ {
lastTarg = &players[lastTargID]; lastTarg = players[lastTargID].mo;
} }
} }
if (player->throwdir == -1) if (player->throwdir == -1)
{ {
// Backwards Jawz targets yourself. // Backwards Jawz targets yourself.
targ = player; targ = player->mo;
player->jawztargetdelay = 0; player->jawztargetdelay = 0;
} }
else else
@ -7970,9 +7984,14 @@ void K_KartPlayerAfterThink(player_t *player)
targ = K_FindJawzTarget(player->mo, player, ANGLE_45); 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. // Increment delay.
if (player->jawztargetdelay < 10) if (player->jawztargetdelay < 10)
@ -7991,33 +8010,33 @@ void K_KartPlayerAfterThink(player_t *player)
else else
{ {
// Allow a swap. // Allow a swap.
if (P_IsDisplayPlayer(player) || P_IsDisplayPlayer(targ)) if (P_IsDisplayPlayer(player) || P_IsDisplayPlayer(targ->player))
{ {
S_StartSound(NULL, sfx_s3k89); S_StartSound(NULL, sfx_s3k89);
} }
else else
{ {
S_StartSound(targ->mo, sfx_s3k89); S_StartSound(targ, sfx_s3k89);
} }
player->lastjawztarget = targ - players; player->lastjawztarget = targID;
player->jawztargetdelay = 5; 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->lastjawztarget = -1;
player->jawztargetdelay = 0; player->jawztargetdelay = 0;
return; return;
} }
ret = P_SpawnMobj(targ->mo->x, targ->mo->y, targ->mo->z, MT_PLAYERRETICULE); ret = P_SpawnMobj(targ->x, targ->y, targ->z, MT_PLAYERRETICULE);
ret->old_x = targ->mo->old_x; ret->old_x = targ->old_x;
ret->old_y = targ->mo->old_y; ret->old_y = targ->old_y;
ret->old_z = targ->mo->old_z; ret->old_z = targ->old_z;
P_SetTarget(&ret->target, targ->mo); P_SetTarget(&ret->target, targ);
ret->frame |= ((leveltime % 10) / 2); ret->frame |= ((leveltime % 10) / 2);
ret->tics = 1; ret->tics = 1;
ret->color = player->skincolor; ret->color = player->skincolor;

View file

@ -118,7 +118,7 @@ void K_UpdateHnextList(player_t *player, boolean clean);
void K_DropHnextList(player_t *player, boolean keepshields); void K_DropHnextList(player_t *player, boolean keepshields);
void K_RepairOrbitChain(mobj_t *orbit); 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); 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); INT32 K_GetKartRingPower(player_t *player, boolean boosted);
void K_UpdateDistanceFromFinishLine(player_t *const player); void K_UpdateDistanceFromFinishLine(player_t *const player);
boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y); boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y);

View file

@ -59,6 +59,7 @@ mobj_t *Obj_SpawnBrolyKi(mobj_t *source, tic_t duration);
/* Special Stage UFO */ /* Special Stage UFO */
void Obj_SpecialUFOThinker(mobj_t *bomb); 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); mobj_t *Obj_CreateSpecialUFO(void);
UINT32 K_GetSpecialUFODistance(void); UINT32 K_GetSpecialUFODistance(void);

View file

@ -140,17 +140,21 @@ static void JawzChase(mobj_t *th, boolean grounded)
if (jawz_chase(th) == NULL || P_MobjWasRemoved(jawz_chase(th)) == true) if (jawz_chase(th) == NULL || P_MobjWasRemoved(jawz_chase(th)) == true)
{ {
mobj_t *newChase = NULL;
player_t *owner = NULL;
th->angle = K_MomentumAngle(th); th->angle = K_MomentumAngle(th);
if (jawz_owner(th) != NULL && P_MobjWasRemoved(jawz_owner(th)) == false if ((jawz_owner(th) != NULL && P_MobjWasRemoved(jawz_owner(th)) == false)
&& jawz_owner(th)->player != NULL) && (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) newChase = K_FindJawzTarget(th, owner, ANGLE_90);
{ if (newChase != NULL)
P_SetTarget(&jawz_chase(th), newPlayer->mo); {
} P_SetTarget(&jawz_chase(th), newChase);
} }
} }

View file

@ -7,8 +7,8 @@
// terms of the GNU General Public License, version 2. // terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details. // See the 'LICENSE' file for more details.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
/// \file shrink.c /// \file ufo.c
/// \brief Shrink laser item code. /// \brief Special Stage UFO
#include "../doomdef.h" #include "../doomdef.h"
#include "../doomstat.h" #include "../doomstat.h"
@ -24,11 +24,11 @@
#include "../k_waypoint.h" #include "../k_waypoint.h"
#include "../k_specialstage.h" #include "../k_specialstage.h"
#define UFO_BASE_SPEED (12 * FRACUNIT) // UFO's slowest speed. #define UFO_BASE_SPEED (16 * FRACUNIT) // UFO's slowest speed.
#define UFO_SPEEDUP (FRACUNIT) #define UFO_SPEEDUP (FRACUNIT >> 3)
#define UFO_SLOWDOWN (FRACUNIT >> 2) #define UFO_SLOWDOWN (FRACUNIT >> 2)
#define UFO_SPACING (1024 * FRACUNIT) #define UFO_SPACING (1024 * FRACUNIT)
#define UFO_DEADZONE (512 * FRACUNIT) #define UFO_DEADZONE (768 * FRACUNIT)
#define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10) #define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10)
#define ufo_waypoint(o) ((o)->extravalue1) #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); 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) static void UFOUpdateDistanceToFinish(mobj_t *ufo)
{ {
waypoint_t *finishLine = K_GetFinishLineWaypoint(); 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) void Obj_SpecialUFOThinker(mobj_t *ufo)
{ {
UFOMove(ufo); UFOMove(ufo);
UFOUpdateAngle(ufo); UFOUpdateAngle(ufo);
UFOUpdateDistanceToFinish(ufo); UFOUpdateDistanceToFinish(ufo);
UFOUpdateSpeed(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) static mobj_t *InitSpecialUFO(waypoint_t *start)
{ {
mobj_t *ufo = NULL; mobj_t *ufo = NULL;
mobj_t *underlay = NULL;
if (start == NULL) if (start == NULL)
{ {
@ -343,6 +417,13 @@ static mobj_t *InitSpecialUFO(waypoint_t *start)
ufo_speed(ufo) = UFO_BASE_SPEED; 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; return ufo;
} }

View file

@ -2222,6 +2222,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
} }
else else
{ {
if (target->type == MT_SPECIAL_UFO)
{
return Obj_SpecialUFODamage(target, inflictor, source, damagetype);
}
if (damagetype & DMG_STEAL) if (damagetype & DMG_STEAL)
{ {
// Not a player, steal damage is intended to not do anything // Not a player, steal damage is intended to not do anything