From df17ba38b9db6e79188e951a430afcc5e7919fee Mon Sep 17 00:00:00 2001 From: Antonio Martinez Date: Mon, 11 Aug 2025 00:52:38 -0400 Subject: [PATCH 1/6] Take snapshotmaps on leveltime 5 --- src/d_clisrv.c | 30 ++++++++++++++++++++++++++++++ src/p_setup.cpp | 29 ----------------------------- 2 files changed, 30 insertions(+), 29 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 9b1d9fb31..813bbb277 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -6743,6 +6743,36 @@ boolean TryRunTics(tic_t realtics) P_PostLoadLevel(); } + // Complete dipshit location for this code, but we do sort of need to + // delay snapshotmaps to cover for elements that are set up on tic 0 + if (roundqueue.snapshotmaps == true && leveltime == 5) + { + if (roundqueue.size > 0) + { + D_TakeMapSnapshots(); + + G_GetNextMap(); + + // roundqueue is wiped after the last round, but + // preserve this to track state into the Podium! + roundqueue.snapshotmaps = true; + + G_NextLevel(); + } + else + { + // Podium: snapshotmaps is finished. Yay! + HU_DoTitlecardCEcho(NULL, va("Congratulations,\\%s!\\Check the console!", cv_playername[0].string), true); + + livestudioaudience_timer = 0; + LiveStudioAudience(); + + CONS_Printf("\n\n\x83""snapshotmaps: Find your images in %s\n", srb2home); + + roundqueue.snapshotmaps = false; + } + } + boolean run = (gametic % NEWTICRATERATIO) == 0; if (run && tickInterp) diff --git a/src/p_setup.cpp b/src/p_setup.cpp index 5e2987d4e..426560456 100644 --- a/src/p_setup.cpp +++ b/src/p_setup.cpp @@ -9093,35 +9093,6 @@ void P_PostLoadLevel(void) // We're now done loading the level. levelloading = false; - if (roundqueue.snapshotmaps == true) - { - if (roundqueue.size > 0) - { - D_TakeMapSnapshots(); - - G_GetNextMap(); - - // roundqueue is wiped after the last round, but - // preserve this to track state into the Podium! - roundqueue.snapshotmaps = true; - - G_NextLevel(); - return; - } - else - { - // Podium: snapshotmaps is finished. Yay! - HU_DoTitlecardCEcho(NULL, va("Congratulations,\\%s!\\Check the console!", cv_playername[0].string), true); - - livestudioaudience_timer = 0; - LiveStudioAudience(); - - CONS_Printf("\n\n\x83""snapshotmaps: Find your images in %s\n", srb2home); - - roundqueue.snapshotmaps = false; - } - } - TracyCZoneEnd(__zone); } From 874b0683ef87448a0db4aaeec1a33436cb073d9b Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 18 Aug 2025 19:14:25 +0100 Subject: [PATCH 2/6] Set up fake Blend Eye state for snapshotmaps - Extracted functions so some state can be set up at spawn - Fake Puyo chamber load for snapshotmaps - Mobj starts off at shadowscale 0, but gets full-size when leaving the ground for the first time --- src/objects/versus/blendeye.c | 149 +++++++++++++++++++++------------- src/p_mobj.c | 1 + 2 files changed, 92 insertions(+), 58 deletions(-) diff --git a/src/objects/versus/blendeye.c b/src/objects/versus/blendeye.c index 435f7f278..abe2a25f8 100644 --- a/src/objects/versus/blendeye.c +++ b/src/objects/versus/blendeye.c @@ -53,6 +53,73 @@ typedef enum /// - MAIN BODY - /// +static void VS_BlendEye_Eye_Parts(mobj_t *mobj, INT32 angledelta) +{ + fixed_t x, y; + + // Before angle update, move the shield. + if (mobj->tracer && mobj->tracer->hnext && mobj->movedir < BLENDEYE_EXPLODING) + { + mobj_t *ref = mobj->tracer->hnext; + while (ref) + { + x = mobj->x + P_ReturnThrustX(mobj, mobj->tracer->movedir + ref->movedir, 40*mobj->scale); + y = mobj->y + P_ReturnThrustY(mobj, mobj->tracer->movedir + ref->movedir, 40*mobj->scale); + P_MoveOrigin(ref, x, y, mobj->z); + ref->angle = mobj->tracer->movedir + ref->movedir - ANGLE_90; + ref = ref->hnext; + } + mobj->tracer->movedir = mobj->angle; + } + + if (mobj->movedir != BLENDEYE_PINCH_DRILLING || mobj->movecount > TICRATE/2) + mobj->angle += angledelta; + + // And after, move the eye. + if (mobj->tracer) + { + x = mobj->x + P_ReturnThrustX(mobj, mobj->angle, 38*mobj->scale); + y = mobj->y + P_ReturnThrustY(mobj, mobj->angle, 38*mobj->scale); + P_MoveOrigin(mobj->tracer, x, y, mobj->z + (mobj->height - mobj->tracer->height)/2); + mobj->tracer->angle = mobj->angle - ANGLE_90; + if (mobj->tracer->hprev) + { + P_MoveOrigin(mobj->tracer->hprev, mobj->x, mobj->y, max(mobj->floorz, mobj->z - (mobj->tracer->hprev->height))); + } + } +} + +static mobj_t *VS_BlendEye_LoadAmmo(mobj_t *mobj, INT32 id) +{ + angle_t ang = mobj->tracer->cusval + FixedAngle(id*360*FRACUNIT/3); + fixed_t h = mobj->z + mobj->height - 4*mapobjectscale; + fixed_t dist = mobj->cvmem - 2*FRACUNIT; + if (id <= 3) + ang += ANGLE_180; + + mobj_t *ammo = P_SpawnMobjFromMobj(mobj, + P_ReturnThrustX(mobj, ang, dist), + P_ReturnThrustY(mobj, ang, dist), + 256*FRACUNIT, + MT_BLENDEYE_PUYO); + P_SetScale(ammo, (ammo->destscale *= 2)); + + if (id <= 3) + h += ammo->height; + else + ammo->cusval = (id-3)*TICRATE; + + P_SetObjectMomZ(ammo, -10*FRACUNIT, false); + ammo->angle = ang; + ammo->cvmem = dist; + ammo->movefactor = (TICRATE/2) + P_RandomKey(PR_MOVINGTARGET, TICRATE/8); + P_SetTarget(&ammo->tracer, mobj); + ammo->extravalue1 = h; + ammo->flags2 |= MF2_STRONGBOX; + + return ammo; +} + void VS_BlendEye_Init(mobj_t *mobj) { UINT8 i; @@ -137,6 +204,10 @@ void VS_BlendEye_Init(mobj_t *mobj) mobj->reactiontime = mobj->z + (3*mobj->height)/2; + mobj->cvmem = 24*FRACUNIT; + + VS_BlendEye_Eye_Parts(mobj, 0); + { const char *enemyname, *subtitle; if (!encoremode) @@ -153,6 +224,23 @@ void VS_BlendEye_Init(mobj_t *mobj) K_InitBossHealthBar(enemyname, subtitle, 0, mobj->tracer->health*(FRACUNIT/mobj->health), mobj->tracer->cvmem); K_DeclareWeakspot(mobj, SPOT_NONE, EYECOLOR, true); } + + if (roundqueue.snapshotmaps) + { + mobj->tracer->cusval = ANGLE_45/2; // chosen by dice roll guaranteed to be random + + // Test load + for (i = 6; i > 0; i--) + { + mobj_t *ammo = VS_BlendEye_LoadAmmo(mobj, i); + ammo->momz = 0; + ammo->z = ammo->extravalue1; + ammo->flags |= MF_NOGRAVITY; + P_SetMobjState(ammo, S_BLENDEYE_PUYO); + if (i != 6) // one random + ammo->sprite = mobj->movedir = SPR_PUYA + i - 1; + } + } } static mobj_t *sourceofmurder; @@ -240,32 +328,7 @@ void VS_BlendEye_Thinker(mobj_t *mobj) // SPAWN YOUR AMMO if ((mobj->movecount % 5) == 0) { - i = (mobj->movecount/5); - angle_t ang = mobj->tracer->cusval + FixedAngle(i*360*FRACUNIT/3); - fixed_t h = mobj->z + mobj->height - 4*mapobjectscale; - fixed_t dist = mobj->cvmem - 2*FRACUNIT; - if (i <= 3) - ang += ANGLE_180; - - mobj_t *ammo = P_SpawnMobjFromMobj(mobj, - P_ReturnThrustX(mobj, ang, dist), - P_ReturnThrustY(mobj, ang, dist), - 256*FRACUNIT, - MT_BLENDEYE_PUYO); - P_SetScale(ammo, (ammo->destscale *= 2)); - - if (i <= 3) - h += ammo->height; - else - ammo->cusval = (i-3)*TICRATE; - - P_SetObjectMomZ(ammo, -10*FRACUNIT, false); - ammo->angle = ang; - ammo->cvmem = dist; - ammo->movefactor = (TICRATE/2) + P_RandomKey(PR_MOVINGTARGET, TICRATE/8); - P_SetTarget(&ammo->tracer, mobj); - ammo->extravalue1 = h; - ammo->flags2 |= MF2_STRONGBOX; + VS_BlendEye_LoadAmmo(mobj, (mobj->movecount/5)); } if ((--mobj->movecount) == 0) @@ -327,6 +390,7 @@ void VS_BlendEye_Thinker(mobj_t *mobj) { // PINCH TRANSITION BEGIN ! mobj->rollangle = 0; + mobj->shadowscale = FRACUNIT; mobj->movedir = BLENDEYE_PINCH_THROWN; mobj_t *ref = mobj->hnext; mobj_t *refnext = NULL; @@ -880,7 +944,6 @@ void VS_BlendEye_Thinker(mobj_t *mobj) mobj->movedir = BLENDEYE_LOADAMMO; mobj->movecount = 6*5; mobj->tracer->cusval = FixedAngle(P_RandomKey(PR_MOVINGTARGET, 360)*FRACUNIT); - mobj->cvmem = 24*FRACUNIT; } else if (mobj->movecount == TICRATE) { @@ -900,7 +963,6 @@ void VS_BlendEye_Thinker(mobj_t *mobj) // Look around. if (mobj->target) // !deathwatch { - fixed_t x, y; INT32 angledelta = AngleDeltaSigned(R_PointToAngle2(mobj->x, mobj->y, mobj->target->x, mobj->target->y), mobj->angle)/4; const INT32 maxdelta = (ANGLE_45/2); @@ -909,36 +971,7 @@ void VS_BlendEye_Thinker(mobj_t *mobj) else if (angledelta < -maxdelta) angledelta = -maxdelta; - // Before angle update, move the shield. - if (mobj->tracer && mobj->tracer->hnext && mobj->movedir < BLENDEYE_EXPLODING) - { - mobj_t *ref = mobj->tracer->hnext; - while (ref) - { - x = mobj->x + P_ReturnThrustX(mobj, mobj->tracer->movedir + ref->movedir, 40*mobj->scale); - y = mobj->y + P_ReturnThrustY(mobj, mobj->tracer->movedir + ref->movedir, 40*mobj->scale); - P_MoveOrigin(ref, x, y, mobj->z); - ref->angle = mobj->tracer->movedir + ref->movedir - ANGLE_90; - ref = ref->hnext; - } - mobj->tracer->movedir = mobj->angle; - } - - if (mobj->movedir != BLENDEYE_PINCH_DRILLING || mobj->movecount > TICRATE/2) - mobj->angle += angledelta; - - // And after, move the eye. - if (mobj->tracer) - { - x = mobj->x + P_ReturnThrustX(mobj, mobj->angle, 38*mobj->scale); - y = mobj->y + P_ReturnThrustY(mobj, mobj->angle, 38*mobj->scale); - P_MoveOrigin(mobj->tracer, x, y, mobj->z + (mobj->height - mobj->tracer->height)/2); - mobj->tracer->angle = mobj->angle - ANGLE_90; - if (mobj->tracer->hprev) - { - P_MoveOrigin(mobj->tracer->hprev, mobj->x, mobj->y, max(mobj->floorz, mobj->z - (mobj->tracer->hprev->height))); - } - } + VS_BlendEye_Eye_Parts(mobj, angledelta); } } diff --git a/src/p_mobj.c b/src/p_mobj.c index 43df4deea..30fb43a47 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11256,6 +11256,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) thing->shadowscale = FRACUNIT/3; break; case MT_SNEAKERPANEL: + case MT_BLENDEYE_MAIN: thing->shadowscale = 0; break; case MT_KURAGEN: From a4ef43442fe90c3babd9862e0f56c4c7f6bbee21 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 18 Aug 2025 17:46:38 +0100 Subject: [PATCH 3/6] Command_CountMobjs_f: Add mobj names to output Was essential for debugging the previous commit --- src/p_tick.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/p_tick.c b/src/p_tick.c index 475f1ebad..151f7b576 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -255,7 +255,13 @@ void Command_CountMobjs_f(void) count++; } - CONS_Printf(M_GetText("There are %d objects of type %d currently in the level.\n"), count, i); + const char *name; + if (i >= MT_FIRSTFREESLOT) + name = FREE_MOBJS[i-MT_FIRSTFREESLOT]; + else + name = MOBJTYPE_LIST[i]; + + CONS_Printf(M_GetText("There are %d objects of type %d (%s) currently in the level.\n"), count, i, name); } return; } @@ -276,7 +282,14 @@ void Command_CountMobjs_f(void) } if (count > 0) // Don't bother displaying if there are none of this type! - CONS_Printf(" * %d: %d\n", i, count); + { + const char *name; + if (i >= MT_FIRSTFREESLOT) + name = FREE_MOBJS[i-MT_FIRSTFREESLOT]; + else + name = MOBJTYPE_LIST[i]; + CONS_Printf(" * %d (%s): %d\n", i, name, count); + } } } From f35d207c7f15a4935ae54ce10a079c7defd52ea2 Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 18 Aug 2025 17:44:14 +0100 Subject: [PATCH 4/6] R_ThingVisible: Add missing entries/cleanup for sanity - MT_EXPLODE is spawned by MT_RANDOMITEM on certain types of pop-in - MT_DUELBOMB and MT_MINERADIUS are both Duel hazard visuals that were missing - MT_FOLLOWER is added to match MT_PLAYER - Add comments to make clear why/how we're dividing this stuff --- src/r_things.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/r_things.cpp b/src/r_things.cpp index 00b8aca5c..9f7a5a147 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -3785,21 +3785,31 @@ boolean R_ThingVisible (mobj_t *thing) { switch (thing->type) { + // Players + case MT_PLAYER: + case MT_FOLLOWER: + // Individual pickups case MT_RING: case MT_FLINGRING: case MT_BLUESPHERE: + case MT_SPRAYCAN: + // Item Boxes and Capsules + case MT_EXPLODE: case MT_RANDOMITEM: case MT_SPHEREBOX: case MT_ITEMCAPSULE: case MT_ITEMCAPSULE_PART: case MT_OVERLAY: // mostly capsule numbers :))) + // Prison Eggs case MT_BATTLECAPSULE: case MT_BATTLECAPSULE_PIECE: - case MT_SPRAYCAN: - case MT_PLAYER: + // Duel hazards + case MT_DUELBOMB: case MT_LANDMINE: case MT_SSMINE: case MT_SSMINE_SHIELD: + case MT_MINERADIUS: + // Checkpoints case MT_CHECKPOINT_END: case MT_SIGNSPARKLE: case MT_THOK: // checkpoint parts From 10ab07b005b24f9c4b524ab2fb880224bf03e48b Mon Sep 17 00:00:00 2001 From: toaster Date: Mon, 18 Aug 2025 20:04:08 +0100 Subject: [PATCH 5/6] Bring `snapshotmaps` into the `map`, `queuemap`, `showmap` fold - Support partial names (but only with quotes around spaces, to accomodate for the multiple course support) - Also permit `snapshotmap` as a command alias, with this one given in the help message --- src/d_netcmd.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index e1608f9f8..91d3a9199 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -448,7 +448,9 @@ void D_RegisterServerCommands(void) COM_AddDebugCommand("eval", Command_Eval); COM_AddCommand("writetextmap", Command_WriteTextmap); - COM_AddCommand("snapshotmaps", Command_SnapshotMaps); + + COM_AddCommand("snapshotmap", Command_SnapshotMaps); + COM_AddCommand("snapshotmaps", Command_SnapshotMaps); // alias // for master server connection AddMServCommands(); @@ -6694,8 +6696,8 @@ static void Command_SnapshotMaps(void) if (COM_Argc() < 2) { CONS_Printf( - "snapshotmaps [map2...]: Create a thumbnail screenshot for the specified levels.\n" - "- Use the full map name, e.g. RR_TestRun.\n" + "snapshotmap [map2...]: Create a thumbnail screenshot for the specified levels.\n" + "- You can do partial names, but no spaces (without \"quotes around them\").\n" "- You can give this command UP TO %d map names and it will create images for all of them.\n" "- This command generates two images -- one 320x200 for the PICTURE lump, another 1024x1024 for rich presence.\n" "- The map requires a \"snapshot camera\" object to have been placed.\n" @@ -6735,23 +6737,31 @@ static void Command_SnapshotMaps(void) roundqueue.snapshotmaps = true; size_t i; + INT32 map; + const char *mapname; + char *realmapname; for (i = 1; i < COM_Argc(); ++i) { - INT32 map = G_MapNumber(COM_Argv(i)); + mapname = COM_Argv(i); + map = G_FindMapByNameOrCode(COM_Argv(i), &realmapname); // G_MapNumber(COM_Argv(i)); - if (map < 0 || map >= nummapheaders) + if (map == 0) { - CONS_Alert(CONS_WARNING, "%s: Map doesn't exist. Not doing anything.\n", COM_Argv(i)); + CONS_Alert(CONS_ERROR, M_GetText("Could not find any map described as '%s'.\nNot snapshotting any maps."), mapname); // clear round queue (to be safe) memset(&roundqueue, 0, sizeof(struct roundqueue)); return; } + map--; + INT32 gt = G_GuessGametypeByTOL(mapheaderinfo[map]->typeoflevel); G_MapIntoRoundQueue(map, gt != -1 ? gt : GT_RACE, false, false); + + Z_Free(realmapname); } D_MapChange(1 + roundqueue.entries[0].mapnum, roundqueue.entries[0].gametype, false, true, 1, false, false); From 66c19015d57f9aa783d4116cc4f36c808b56e489 Mon Sep 17 00:00:00 2001 From: toaster Date: Tue, 19 Aug 2025 13:29:40 +0100 Subject: [PATCH 6/6] Add even more missing duel hazards to the visibility exception list --- src/r_things.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/r_things.cpp b/src/r_things.cpp index 9f7a5a147..058e01f23 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -3809,6 +3809,10 @@ boolean R_ThingVisible (mobj_t *thing) case MT_SSMINE: case MT_SSMINE_SHIELD: case MT_MINERADIUS: + case MT_POGOSPRING: + case MT_DROPTARGET: + case MT_HYUDORO: + case MT_SHADOW: // hyuu fake shadow // Checkpoints case MT_CHECKPOINT_END: case MT_SIGNSPARKLE: