From a0cc5dc69a915bedb495abe0af43a326f58f37e4 Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Wed, 11 Jun 2025 23:45:18 -0400 Subject: [PATCH] WIP amp visuals --- src/deh_tables.c | 2 + src/info.c | 31 +++++++++- src/info.h | 4 ++ src/k_kart.c | 19 ++++++ src/k_kart.h | 1 + src/k_objects.h | 2 + src/objects/CMakeLists.txt | 1 + src/objects/checkpoint.cpp | 9 +++ src/objects/exp.c | 122 +++++++++++++++++++++++++++++++++++++ src/p_enemy.c | 2 +- src/p_mobj.c | 5 ++ 11 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 src/objects/exp.c diff --git a/src/deh_tables.c b/src/deh_tables.c index b8ba3ebea..c6d40380a 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -2686,6 +2686,7 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_EGOORB", "S_AMPS", + "S_EXP", "S_WATERTRAIL1", "S_WATERTRAIL2", @@ -4009,6 +4010,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_PULLUPHOOK", "MT_AMPS", + "MT_EXP", "MT_FLYBOT767", diff --git a/src/info.c b/src/info.c index 559aeab94..8ac7b4eba 100644 --- a/src/info.c +++ b/src/info.c @@ -600,6 +600,8 @@ char sprnames[NUMSPRITES + 1][5] = "AMPC", "AMPD", + "EXPC", + "SOR_", "WTRL", // Water Trail @@ -3246,6 +3248,7 @@ state_t states[NUMSTATES] = {SPR_EGOO, 0, 1, {NULL}, 0, 0, S_NULL}, // S_EGOORB {SPR_AMPA, FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 41, 1, S_NULL}, // S_AMPS + {SPR_EXPC, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_EXP // Water Trail {SPR_WTRL, FF_PAPERSPRITE , 2, {NULL}, 0, 0, S_NULL}, // S_WATERTRAIL1 @@ -22482,7 +22485,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, { // MT_AMPS - 3444, // doomednum + -1, // doomednum S_AMPS, // spawnstate 1000, // spawnhealth S_NULL, // seestate @@ -22507,6 +22510,32 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_NOCLIPTHING, // flags S_NULL // raisestate }, + { // MT_EXP + -1, // doomednum + S_EXP, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 0, // 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 + 1, // speed + 32*FRACUNIT, // radius + 32*FRACUNIT, // height + 0, // dispoffset + 0, // mass + 0, // damage + sfx_None, // activesound + MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_NOCLIP|MF_NOCLIPTHING, // flags + S_NULL // raisestate + }, { // MT_FLYBOT767 -1, // doomednum S_FLYBOT767, // spawnstate diff --git a/src/info.h b/src/info.h index 737daf64b..e6df879b5 100644 --- a/src/info.h +++ b/src/info.h @@ -1141,6 +1141,8 @@ typedef enum sprite SPR_AMPC, SPR_AMPD, + SPR_EXPC, + SPR_SOR_, SPR_WTRL, // Water Trail @@ -3742,6 +3744,7 @@ typedef enum state S_EGOORB, S_AMPS, + S_EXP, S_WATERTRAIL1, S_WATERTRAIL2, @@ -5091,6 +5094,7 @@ typedef enum mobj_type MT_PULLUPHOOK, MT_AMPS, + MT_EXP, MT_FLYBOT767, diff --git a/src/k_kart.c b/src/k_kart.c index a8793558c..41aca4318 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -4229,6 +4229,25 @@ void K_SpawnAmps(player_t *player, UINT8 amps, mobj_t *impact) } } +void K_SpawnEXP(player_t *player, UINT8 exp, mobj_t *impact) +{ + if (exp == 0) + return; + + for (int i = 0; i < exp; i++) + { + mobj_t *pickup = P_SpawnMobj(impact->x, impact->y, impact->z, MT_EXP); + pickup->momx = impact->momx; + pickup->momy = impact->momy; + pickup->momz = impact->momz; + pickup->momx += P_RandomRange(PR_ITEM_DEBRIS, -20*mapobjectscale, 20*mapobjectscale); + pickup->momy += P_RandomRange(PR_ITEM_DEBRIS, -20*mapobjectscale, 20*mapobjectscale); + pickup->momz += P_RandomRange(PR_ITEM_DEBRIS, -20*mapobjectscale, 20*mapobjectscale); + // pickup->color = player->skincolor; + P_SetTarget(&pickup->target, player->mo); + } +} + void K_AwardPlayerAmps(player_t *player, UINT8 amps) { UINT16 getamped = player->amps + amps; diff --git a/src/k_kart.h b/src/k_kart.h index 738513358..1b2804e93 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -159,6 +159,7 @@ angle_t K_MomentumAngleReal(const mobj_t *mo); #define K_MomentumAngle(mo) K_MomentumAngleEx(mo, 6 * mo->scale) boolean K_PvPAmpReward(UINT32 award, player_t *attacker, player_t *defender); void K_SpawnAmps(player_t *player, UINT8 amps, mobj_t *impact); +void K_SpawnEXP(player_t *player, UINT8 exp, mobj_t *impact); void K_AwardPlayerAmps(player_t *player, UINT8 amps); void K_CheckpointCrossAward(player_t *player); void K_AwardPlayerRings(player_t *player, UINT16 rings, boolean overload); diff --git a/src/k_objects.h b/src/k_objects.h index b1b9b8a93..f5c36da12 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -146,6 +146,8 @@ void Obj_AmpBurstThink(mobj_t *amp); void Obj_AmpsThink(mobj_t *amps); +void Obj_ExpThink(mobj_t *exp); + void Obj_ChargeAuraThink(mobj_t *aura); void Obj_ChargeFallThink(mobj_t *charge); void Obj_ChargeReleaseThink(mobj_t *release); diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index f050047ca..8d339d8f4 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -65,6 +65,7 @@ target_sources(SRB2SDL2 PRIVATE lightning-shield.cpp flame-shield.cpp stone-shoe.cpp + exp.c ) add_subdirectory(versus) diff --git a/src/objects/checkpoint.cpp b/src/objects/checkpoint.cpp index 81b546400..0d2883a4f 100644 --- a/src/objects/checkpoint.cpp +++ b/src/objects/checkpoint.cpp @@ -688,8 +688,17 @@ void Obj_CrossCheckpoints(player_t* player, fixed_t old_x, fixed_t old_y) player->checkpointId = chk->id(); + UINT16 oldexp = player->exp; + K_CheckpointCrossAward(player); + if (player->exp > oldexp) + { + UINT16 expdiff = (player->exp - oldexp); + K_SpawnEXP(player, expdiff, chk); + K_SpawnEXP(player, expdiff, chk->other()); + } + K_UpdatePowerLevels(player, player->laps, false); } diff --git a/src/objects/exp.c b/src/objects/exp.c new file mode 100644 index 000000000..e6fd454d4 --- /dev/null +++ b/src/objects/exp.c @@ -0,0 +1,122 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2025 by AJ "Tyron" Martinez. +// Copyright (C) 2025 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file amps.c +/// \brief EXP VFX code. + +#include "../doomdef.h" +#include "../info.h" +#include "../k_objects.h" +#include "../p_local.h" +#include "../k_kart.h" +#include "../k_powerup.h" +#include "../m_random.h" +#include "../r_main.h" +#include "../m_easing.h" +#include "../s_sound.h" +#include "../sounds.h" + +#define EXP_ARCTIME (8) +#define EXP_ORBIT (240) +#define EXP_COLLECT (100) + +void Obj_ExpThink (mobj_t *exp) +{ + if (P_MobjWasRemoved(exp->target) + || exp->target->health == 0 + || exp->target->destscale <= 1 // sealed star fall out + || !exp->target->player) + { + P_RemoveMobj(exp); + } + else + { + mobj_t *mo = exp->target; + player_t *player = mo->player; + + fixed_t dist, fakez; + angle_t hang, vang; + + dist = P_AproxDistance(P_AproxDistance(exp->x - mo->x, exp->y - mo->y), exp->z - mo->z); + + exp->angle += ANGLE_45/4; + + if (exp->threshold) + { + A_AttractChase(exp); + + exp->threshold = min(exp->threshold, 1); + + dist = P_AproxDistance(P_AproxDistance(exp->x - mo->x, exp->y - mo->y), exp->z - mo->z); + + if (dist < (EXP_COLLECT * exp->scale)) + P_RemoveMobj(exp); + + return; + } + + UINT8 damper = 3; + + fixed_t vert = dist/3; + fixed_t speed = 45*exp->scale; + + exp->cusval++; + + if (exp->extravalue2) // Mode: going down, aim at the player and speed up / dampen stray movement + { + if (exp->extravalue1) + exp->extravalue1--; + + exp->extravalue2++; + + speed += exp->extravalue2 * exp->scale/2; + + fakez = mo->z + (vert * exp->extravalue1 / EXP_ARCTIME); + damper = 1; + } + else // Mode: going up, aim above the player + { + exp->extravalue1++; + if (exp->extravalue1 >= EXP_ARCTIME) + exp->extravalue2 = 1; + + fakez = mo->z + vert; + } + + if (mo->flags & MFE_VERTICALFLIP) + fakez -= mo->height/2; + else + fakez += mo->height/2; + + hang = R_PointToAngle2(exp->x, exp->y, mo->x, mo->y); + vang = R_PointToAngle2(exp->z, 0, fakez, dist); + + exp->momx -= exp->momx>>(damper), exp->momy -= exp->momy>>(damper), exp->momz -= exp->momz>>(damper); + exp->momx += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINECOSINE(hang>>ANGLETOFINESHIFT), speed)); + exp->momy += FixedMul(FINESINE(vang>>ANGLETOFINESHIFT), FixedMul(FINESINE(hang>>ANGLETOFINESHIFT), speed)); + exp->momz += FixedMul(FINECOSINE(vang>>ANGLETOFINESHIFT), speed); + + if (exp->cusval%2) + { + mobj_t *ghost = P_SpawnGhostMobj(exp); + ghost->colorized = true; + ghost->color = player->skincolor; + ghost->renderflags |= RF_ADD; + ghost->fuse = 1; + } + + if (dist < (EXP_ORBIT * exp->scale) && exp->extravalue2) + { + P_SetTarget(&exp->tracer, exp->target); + exp->threshold = TICRATE; + exp->extravalue1 = 0; + exp->extravalue2 = 0; + } + } +} \ No newline at end of file diff --git a/src/p_enemy.c b/src/p_enemy.c index 3006b7369..36d2ec1f1 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -3501,7 +3501,7 @@ void A_AttractChase(mobj_t *actor) if (actor->flags2 & MF2_NIGHTSPULL || !actor->health) return; - if (actor->extravalue1 && actor->type != MT_EMERALD) // SRB2Kart + if (actor->extravalue1 && actor->type != MT_EMERALD && actor->type != MT_EXP) // SRB2Kart { if (!actor->target || P_MobjWasRemoved(actor->target) || !actor->target->player) { diff --git a/src/p_mobj.c b/src/p_mobj.c index a4011d24d..da3e08bc6 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8908,6 +8908,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_AmpsThink(mobj); break; } + case MT_EXP: + { + Obj_ExpThink(mobj); + break; + } case MT_BLOCKRING: { Obj_BlockRingThink(mobj);