From 4857d48633bdbef34f436bc77677b108ec6b648d Mon Sep 17 00:00:00 2001 From: James R Date: Sat, 19 Aug 2023 03:40:17 -0700 Subject: [PATCH] Add "twinkle" lens flare to emeralds - Battle: plays once the orbiting collection animation finishes and the player's emerald flags are updated - Centered on the player - Sealed Star: plays as soon as the orbiting animation begins - Centered on the emerald --- src/deh_tables.c | 3 ++ src/info.c | 29 +++++++++++++++++++ src/info.h | 3 ++ src/k_objects.h | 1 + src/objects/emerald.c | 67 +++++++++++++++++++++++++++++++++++++++++++ src/p_mobj.c | 8 ++++++ 6 files changed, 111 insertions(+) diff --git a/src/deh_tables.c b/src/deh_tables.c index 97a78e936..0196e2086 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -1208,6 +1208,8 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_EMERALDSPARK6", "S_EMERALDSPARK7", + "S_EMERALDFLARE1", + // Emerald hunt shards "S_SHRD1", "S_SHRD2", @@ -4807,6 +4809,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_EMBLEM", "MT_EMERALD", "MT_EMERALDSPARK", + "MT_EMERALDFLARE", "MT_EMERHUNT", // Emerald Hunt "MT_EMERALDSPAWN", // Emerald spawner w/ delay diff --git a/src/info.c b/src/info.c index a3d358d7e..f21641943 100644 --- a/src/info.c +++ b/src/info.c @@ -1878,6 +1878,8 @@ state_t states[NUMSTATES] = {SPR_ESPK, FF_FULLBRIGHT|5, 3, {NULL}, 0, 0, S_EMERALDSPARK7}, // S_EMERALDSPARK6 {SPR_ESPK, FF_FULLBRIGHT|6, 3, {NULL}, 0, 0, S_NULL}, // S_EMERALDSPARK7 + {SPR_LENS, FF_FULLBRIGHT|FF_ADD|FF_TRANS10|FF_ANIMATE|11, 8, {NULL}, 7, 1, S_GAINAX_MID2}, // S_EMERALDFLARE1 + // Emerald hunt shards {SPR_SHRD, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD1 {SPR_SHRD, 1, -1, {NULL}, 0, 0, S_NULL}, // S_SHRD2 @@ -8330,6 +8332,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_EMERALDFLARE + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 8*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, + { // MT_EMERHUNT 320, // doomednum S_SHRD1, // spawnstate diff --git a/src/info.h b/src/info.h index 9dc14922b..81e6554bc 100644 --- a/src/info.h +++ b/src/info.h @@ -2362,6 +2362,8 @@ typedef enum state S_EMERALDSPARK6, S_EMERALDSPARK7, + S_EMERALDFLARE1, + // Emerald hunt shards S_SHRD1, S_SHRD2, @@ -5996,6 +5998,7 @@ typedef enum mobj_type MT_EMBLEM, MT_EMERALD, MT_EMERALDSPARK, + MT_EMERALDFLARE, MT_EMERHUNT, // Emerald Hunt MT_EMERALDSPAWN, // Emerald spawner w/ delay diff --git a/src/k_objects.h b/src/k_objects.h index 3cb031229..79afc08cb 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -207,6 +207,7 @@ void Obj_SneakerPanelCollide(mobj_t *pad, mobj_t *mo); /* Emerald */ void Obj_SpawnEmeraldSparks(mobj_t *source); void Obj_EmeraldThink(mobj_t *emerald); +void Obj_EmeraldFlareThink(mobj_t *flare); void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT32 revolution_time, tic_t fuse); void Obj_GiveEmerald(mobj_t *emerald); diff --git a/src/objects/emerald.c b/src/objects/emerald.c index 4c428ea12..7d70e400c 100644 --- a/src/objects/emerald.c +++ b/src/objects/emerald.c @@ -1,5 +1,6 @@ #include "../k_battle.h" #include "../k_objects.h" +#include "../k_specialstage.h" #include "../info.h" #include "../m_random.h" #include "../p_local.h" @@ -163,6 +164,70 @@ void Obj_EmeraldThink(mobj_t *emerald) K_BattleOvertimeKiller(emerald); } +void Obj_EmeraldFlareThink(mobj_t *flare) +{ + const INT32 kExtraTics = 3; + const INT32 flare_tics = states[S_EMERALDFLARE1].tics + kExtraTics; + + if (P_MobjWasRemoved(flare->target)) + { + P_RemoveMobj(flare); + return; + } + + // Target is assumed to be the emerald in orbit. When + // emerald fuse runs out, it shall update player's emerald + // flags. Time the flare animation so it ends with the + // emerald fuse. + if (!flare->fuse && flare->target->fuse > flare_tics) + { + return; + } + + if (flare->state == &states[S_INVISIBLE]) + { + // In special stages, just follow the emerald. + if (specialstageinfo.valid == false) + { + // Update target to player. We don't need to track + // the emerald anymore. + P_SetTarget(&flare->target, flare->target->target); + + if (P_MobjWasRemoved(flare->target)) + { + P_RemoveMobj(flare); + return; + } + } + + P_SetMobjState(flare, S_EMERALDFLARE1); + flare->fuse = flare_tics; + } + + // Focus on center of player. + P_SetOrigin(flare, flare->target->x, flare->target->y, center_of(flare->target)); +} + +static void spawn_lens_flare(mobj_t *emerald) +{ + mobj_t *flare = P_SpawnMobjFromMobj(emerald, 0, 0, 0, MT_EMERALDFLARE); + + P_SetTarget(&flare->target, emerald); + P_InstaScale(flare, emerald->target->scale); + + flare->color = emerald->color; + flare->colorized = true; + + flare->renderflags |= RF_ALWAYSONTOP; + + // FIXME: linkdraw doesn't work consistently, so I drew it on top of everyting (and through walls) +#if 0 + P_SetTarget(&flare->tracer, emerald->target); + flare->flags2 |= MF2_LINKDRAW; + flare->dispoffset = 1000; +#endif +} + void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT32 revolution_time, tic_t fuse) { P_SetTarget(&emerald->target, target); @@ -185,6 +250,8 @@ void Obj_BeginEmeraldOrbit(mobj_t *emerald, mobj_t *target, fixed_t radius, INT3 emerald->flags |= MF_NOGRAVITY | MF_NOCLIP | MF_NOCLIPTHING | MF_NOCLIPHEIGHT; emerald->shadowscale = 0; + + spawn_lens_flare(emerald); } void Obj_GiveEmerald(mobj_t *emerald) diff --git a/src/p_mobj.c b/src/p_mobj.c index de0e233f5..244be1ba3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7551,6 +7551,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj) case MT_EMERALD: Obj_EmeraldThink(mobj); + if (P_MobjWasRemoved(mobj)) + { + return false; + } + break; + case MT_EMERALDFLARE: + Obj_EmeraldFlareThink(mobj); + if (P_MobjWasRemoved(mobj)) { return false;