diff --git a/src/info.c b/src/info.c index 993039457..e3bbf3b2a 100644 --- a/src/info.c +++ b/src/info.c @@ -22348,12 +22348,12 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_kc2e, // deathsound 60*FRACUNIT, // speed 48*FRACUNIT, // radius - 48*FRACUNIT, // height + 64*FRACUNIT, // height 0, // display offset 100, // mass MT_RANDOMITEMPOP, // damage sfx_None, // activesound - MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + MF_NOSQUISH|MF_PICKUPFROMBELOW|MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_RANDOMITEM1 // raisestate }, @@ -22375,12 +22375,12 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_kc2e, // deathsound 60*FRACUNIT, // speed 48*FRACUNIT, // radius - 48*FRACUNIT, // height + 64*FRACUNIT, // height 0, // display offset 100, // mass MT_RANDOMITEMPOP, // damage sfx_None, // activesound - MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + MF_NOSQUISH|MF_PICKUPFROMBELOW|MF_SLIDEME|MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, @@ -23271,7 +23271,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_cdfm28, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_NOSQUISH|MF_PICKUPFROMBELOW|MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23298,7 +23298,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags + MF_NOSQUISH|MF_PICKUPFROMBELOW|MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, diff --git a/src/k_kart.c b/src/k_kart.c index 0b730306f..fa8828057 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -241,44 +241,6 @@ void K_ReduceVFX(mobj_t *mo, player_t *owner) } } -player_t *K_GetItemBoxPlayer(mobj_t *mobj) -{ - fixed_t closest = INT32_MAX; - player_t *player = NULL; - UINT8 i; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (!(playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo) && !players[i].spectator)) - { - continue; - } - - // Always use normal item box rules -- could pass in "2" for fakes but they blend in better like this - if (P_CanPickupItem(&players[i], 1)) - { - fixed_t dist = P_AproxDistance(P_AproxDistance( - players[i].mo->x - mobj->x, - players[i].mo->y - mobj->y), - players[i].mo->z - mobj->z - ); - - if (dist > 8192*mobj->scale) - { - continue; - } - - if (dist < closest) - { - player = &players[i]; - closest = dist; - } - } - } - - return player; -} - // Angle reflection used by springs & speed pads angle_t K_ReflectAngle(angle_t yourangle, angle_t theirangle, fixed_t yourspeed, fixed_t theirspeed) { @@ -6804,6 +6766,8 @@ static void K_MoveHeldObjects(player_t *player) if (cur->type == MT_EGGMANITEM_SHIELD) { + Obj_RandomItemVisuals(cur); + // Decided that this should use their "canon" color. cur->color = SKINCOLOR_BLACK; } diff --git a/src/k_kart.h b/src/k_kart.h index bf67be518..bddba4024 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -37,7 +37,6 @@ Make sure this matches the actual number of states #define STUMBLE_STEEP_VAL ANG60 #define STUMBLE_STEEP_VAL_AIR (ANG30 + ANG10) -player_t *K_GetItemBoxPlayer(mobj_t *mobj); angle_t K_ReflectAngle(angle_t angle, angle_t against, fixed_t maxspeed, fixed_t yourspeed); void K_RegisterKartStuff(void); diff --git a/src/k_objects.h b/src/k_objects.h index 0852100cc..95a565587 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -118,6 +118,11 @@ void Obj_UpdateRingShooterFace(mobj_t *part); void Obj_AudienceInit(mobj_t * mobj, mapthing_t *mthing, INT32 followerpick); void Obj_AudienceThink(mobj_t * mobj, boolean focusonplayer); +/* Random Item Boxes */ +void Obj_RandomItemVisuals(mobj_t *mobj); +boolean Obj_RandomItemSpawnIn(mobj_t *mobj); +fixed_t Obj_RandomItemScale(fixed_t oldScale); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index 6442860cc..df047fb5d 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -16,4 +16,5 @@ target_sources(SRB2SDL2 PRIVATE drop-target.c ring-shooter.c audience.c + random-item.c ) diff --git a/src/objects/item-debris.c b/src/objects/item-debris.c index 886fd89c0..9558b81af 100644 --- a/src/objects/item-debris.c +++ b/src/objects/item-debris.c @@ -45,8 +45,8 @@ spawn_debris INT32 angle) { const fixed_t height_table[NUM_DEBRIS_TYPES] = { - 50*FRACUNIT, 35*FRACUNIT, + 24*FRACUNIT, }; mobj_t *debris = P_SpawnMobjFromMobj( diff --git a/src/objects/random-item.c b/src/objects/random-item.c new file mode 100644 index 000000000..9abb7cb93 --- /dev/null +++ b/src/objects/random-item.c @@ -0,0 +1,153 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour +// Copyright (C) 2022 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 random-item.c +/// \brief Random item boxes + +#include "../doomdef.h" +#include "../doomstat.h" +#include "../k_objects.h" +#include "../g_game.h" +#include "../p_local.h" +#include "../r_defs.h" +#include "../k_battle.h" +#include "../m_random.h" + +#define FLOAT_HEIGHT ( 12 * FRACUNIT ) +#define FLOAT_TIME ( 2 * TICRATE ) +#define FLOAT_ANGLE ( ANGLE_MAX / FLOAT_TIME ) + +#define SCALE_LO ( FRACUNIT * 2 / 3 ) +#define SCALE_HI ( FRACUNIT ) +#define SCALE_TIME ( 5 * TICRATE / 2 ) +#define SCALE_ANGLE ( ANGLE_MAX / SCALE_TIME ) + +#define item_vfxtimer(o) ((o)->cvmem) + +static player_t *GetItemBoxPlayer(mobj_t *mobj) +{ + fixed_t closest = INT32_MAX; + player_t *player = NULL; + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (!(playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo) && !players[i].spectator)) + { + continue; + } + + // Always use normal item box rules -- could pass in "2" for fakes but they blend in better like this + if (P_CanPickupItem(&players[i], 1)) + { + fixed_t dist = P_AproxDistance(P_AproxDistance( + players[i].mo->x - mobj->x, + players[i].mo->y - mobj->y), + players[i].mo->z - mobj->z + ); + + if (dist > 8192*mobj->scale) + { + continue; + } + + if (dist < closest) + { + player = &players[i]; + closest = dist; + } + } + } + + return player; +} + +static void ItemBoxColor(mobj_t *mobj) +{ + player_t *player = GetItemBoxPlayer(mobj); + skincolornum_t color = SKINCOLOR_BLACK; + + if (player != NULL) + { + color = player->skincolor; + } + + mobj->color = color; + mobj->colorized = false; +} + +static void ItemBoxBob(mobj_t *mobj) +{ + const fixed_t sine = FINESINE((FLOAT_ANGLE * item_vfxtimer(mobj)) >> ANGLETOFINESHIFT); + const fixed_t bob = FixedMul(FLOAT_HEIGHT, sine); + mobj->spriteyoffset = FLOAT_HEIGHT + bob; +} + +static void ItemBoxScaling(mobj_t *mobj) +{ + const fixed_t sine = FINESINE((SCALE_ANGLE * item_vfxtimer(mobj)) >> ANGLETOFINESHIFT); + const fixed_t newScale = SCALE_LO + FixedMul(SCALE_HI - SCALE_LO, (sine + FRACUNIT) >> 1); + mobj->spritexscale = mobj->spriteyscale = newScale; +} + +void Obj_RandomItemVisuals(mobj_t *mobj) +{ + ItemBoxColor(mobj); + ItemBoxBob(mobj); + ItemBoxScaling(mobj); + item_vfxtimer(mobj)++; +} + +boolean Obj_RandomItemSpawnIn(mobj_t *mobj) +{ + if ((leveltime == starttime) && !(gametyperules & GTR_CIRCUIT) && (mobj->flags2 & MF2_BOSSNOTRAP)) // here on map start? + { + if (gametyperules & GTR_PAPERITEMS) + { + if (battleprisons == true) + { + ; + } + else + { + mobj_t *paperspawner = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PAPERITEMSPOT); + paperspawner->spawnpoint = mobj->spawnpoint; + mobj->spawnpoint->mobj = paperspawner; + P_RemoveMobj(mobj); + return false; + } + } + + // poof into existance + P_UnsetThingPosition(mobj); + mobj->flags &= ~(MF_NOCLIPTHING|MF_NOBLOCKMAP); + mobj->renderflags &= ~RF_DONTDRAW; + P_SetThingPosition(mobj); + P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_EXPLODE); + nummapboxes++; + } + + return true; +} + +fixed_t Obj_RandomItemScale(fixed_t oldScale) +{ + const fixed_t intendedScale = oldScale * 3; + const fixed_t maxScale = FixedDiv(128*FRACUNIT, mobjinfo[MT_RANDOMITEM].radius); // don't make them larger than the blockmap can handle + + return min(intendedScale, maxScale); +} + +void Obj_RandomItemSpawn(mobj_t *mobj) +{ + item_vfxtimer(mobj) = P_RandomRange(PR_DECORATION, 0, SCALE_TIME - 1); + + mobj->destscale = Obj_RandomItemScale(mobj->destscale); + P_SetScale(mobj, mobj->destscale); +} diff --git a/src/p_mobj.c b/src/p_mobj.c index 8bc686b4a..2b0bfc036 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7273,18 +7273,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) break; } case MT_EGGMANITEM: - { - player_t *player = K_GetItemBoxPlayer(mobj); - UINT8 color = SKINCOLOR_BLACK; - - if (player != NULL) - { - color = player->skincolor; - } - - mobj->color = color; - mobj->colorized = false; - } + Obj_RandomItemVisuals(mobj); /* FALLTHRU */ case MT_BANANA: mobj->friction = ORIG_FRICTION/4; @@ -7313,7 +7302,7 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (mobj->type == MT_EGGMANITEM) { // Grow to match the actual items - mobj->destscale *= 3; + mobj->destscale = Obj_RandomItemScale(mobj->destscale); } } } @@ -9446,73 +9435,13 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } break; case MT_RANDOMITEM: - if ((leveltime == starttime) && !(gametyperules & GTR_CIRCUIT) && (mobj->flags2 & MF2_BOSSNOTRAP)) // here on map start? + if (Obj_RandomItemSpawnIn(mobj) == false) { - if (gametyperules & GTR_PAPERITEMS) - { - if (battleprisons == true) - { - ; - } - else - { - mobj_t *paperspawner = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PAPERITEMSPOT); - paperspawner->spawnpoint = mobj->spawnpoint; - mobj->spawnpoint->mobj = paperspawner; - P_RemoveMobj(mobj); - return false; - } - } - // poof into existance - P_UnsetThingPosition(mobj); - mobj->flags &= ~(MF_NOCLIPTHING|MF_NOBLOCKMAP); - mobj->renderflags &= ~RF_DONTDRAW; - P_SetThingPosition(mobj); - P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_EXPLODE); - nummapboxes++; + return false; } - // FALLTHRU + /* FALLTHRU */ case MT_SPHEREBOX: - if (mobj->threshold == 70) - { - mobj->color = K_RainbowColor(leveltime); - mobj->colorized = true; - - if ((gametyperules & GTR_OVERTIME) && battleovertime.enabled) - { - angle_t ang = FixedAngle((leveltime % 360) << FRACBITS); - fixed_t z = battleovertime.z; - fixed_t dist; - mobj_t *ghost; - - /*if (z < mobj->subsector->sector->floorheight) - z = mobj->subsector->sector->floorheight;*/ - - if (mobj->extravalue1 < 512) - mobj->extravalue1++; - dist = mobj->extravalue1 * mapobjectscale; - - P_MoveOrigin(mobj, battleovertime.x + P_ReturnThrustX(NULL, ang, dist), - battleovertime.y + P_ReturnThrustY(NULL, ang, dist), z); - - ghost = P_SpawnGhostMobj(mobj); - ghost->fuse = 4; - ghost->frame |= FF_FULLBRIGHT; - } - } - else - { - player_t *player = K_GetItemBoxPlayer(mobj); - UINT8 color = SKINCOLOR_BLACK; - - if (player != NULL) - { - color = player->skincolor; - } - - mobj->color = color; - mobj->colorized = false; - } + Obj_RandomItemVisuals(mobj); break; case MT_MONITOR_PART: Obj_MonitorPartThink(mobj); @@ -9778,8 +9707,6 @@ static boolean P_FuseThink(mobj_t *mobj) // Transfer flags2 (strongbox, objectflip, bossnotrap) newmobj->flags2 = mobj->flags2; - if (mobj->threshold == 70) - newmobj->threshold = 70; } P_RemoveMobj(mobj); // make sure they disappear @@ -10922,8 +10849,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) break; case MT_RANDOMITEM: case MT_SPHEREBOX: - mobj->destscale *= 3; - P_SetScale(mobj, mobj->scale * 3); + Obj_RandomItemSpawn(mobj); break; default: break; @@ -13223,7 +13149,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean // Ambush = double size (grounded) / half size (aerial) if (!(mthing->args[2] & TMICF_INVERTSIZE) == !P_IsObjectOnGround(mobj)) { - mobj->extravalue1 = min(mobj->extravalue1 << 1, FixedDiv(64*FRACUNIT, mobj->info->radius)); // don't make them larger than the blockmap can handle + mobj->extravalue1 = min(mobj->extravalue1 << 1, FixedDiv(128*FRACUNIT, mobj->info->radius)); // don't make them larger than the blockmap can handle mobj->scalespeed <<= 1; } break;