diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 10ff36129..e259c76a2 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -70,6 +70,7 @@ #include "k_powerup.h" #include "k_roulette.h" #include "k_bans.h" +#include "k_director.h" #ifdef SRB2_CONFIG_ENABLE_WEBM_MOVIES #include "m_avrecorder.h" @@ -1461,6 +1462,33 @@ void D_SendPlayerConfig(UINT8 n) WeaponPref_Send(n); } +static camera_t *LocalMutableCamera(INT32 playernum) +{ + if (demo.playback) + { + // TODO: could have splitscreen support + if (!camera[0].freecam) + { + return NULL; + } + + return &camera[0]; + } + + if (G_IsPartyLocal(playernum)) + { + UINT8 viewnum = G_PartyPosition(playernum); + camera_t *cam = &camera[viewnum]; + + if (cam->freecam || (players[playernum].spectator && !K_DirectorIsAvailable(viewnum))) + { + return cam; + } + } + + return NULL; +} + void D_Cheat(INT32 playernum, INT32 cheat, ...) { va_list ap; @@ -1468,12 +1496,62 @@ void D_Cheat(INT32 playernum, INT32 cheat, ...) UINT8 buf[64]; UINT8 *p = buf; + camera_t *cam; + if ((cam = LocalMutableCamera(playernum))) + { + switch (cheat) + { + case CHEAT_RELATIVE_TELEPORT: + va_start(ap, cheat); + cam->x += va_arg(ap, fixed_t); + cam->y += va_arg(ap, fixed_t); + cam->z += va_arg(ap, fixed_t); + va_end(ap); + return; + + case CHEAT_TELEPORT: + va_start(ap, cheat); + cam->x = va_arg(ap, fixed_t); + cam->y = va_arg(ap, fixed_t); + cam->z = va_arg(ap, fixed_t); + va_end(ap); + return; + + case CHEAT_ANGLE: + va_start(ap, cheat); + cam->angle = va_arg(ap, angle_t); + va_end(ap); + return; + + default: + break; + } + } + if (!CV_CheatsEnabled()) { CONS_Printf("This cannot be used without cheats enabled.\n"); return; } + if (demo.playback && cheat == CHEAT_DEVMODE) + { + // There is no networking in demos, but devmode is + // too useful to be inaccessible! + // TODO: maybe allow everything, even though it would + // desync replays? May be useful for debugging. + va_start(ap, cheat); + cht_debug = va_arg(ap, UINT32); + va_end(ap); + return; + } + + // sanity check + if (demo.playback) + { + return; + } + WRITEUINT8(p, playernum); WRITEUINT8(p, cheat); diff --git a/src/m_cheat.c b/src/m_cheat.c index 24a0d26fd..39ccfd16b 100644 --- a/src/m_cheat.c +++ b/src/m_cheat.c @@ -285,6 +285,9 @@ boolean cht_Interpret(const char *password) { CONS_Printf(M_GetText("OBJECTPLACE must be enabled.\n")); return; } #define REQUIRE_INLEVEL if (gamestate != GS_LEVEL || demo.playback)\ +{ CONS_Printf(M_GetText("You must be in a level (and not a replay) to use this.\n")); return; } + +#define REQUIRE_INLEVEL_OR_REPLAY if (gamestate != GS_LEVEL)\ { CONS_Printf(M_GetText("You must be in a level to use this.\n")); return; } #define REQUIRE_SINGLEPLAYER if (netgame)\ @@ -361,7 +364,7 @@ void Command_RTeleport_f(void) float z = atof(COM_Argv(3)); REQUIRE_CHEATS; - REQUIRE_INLEVEL; + REQUIRE_INLEVEL_OR_REPLAY; if (COM_Argc() != 4) { @@ -380,7 +383,7 @@ void Command_Teleport_f(void) float z = atof(COM_Argv(3)); REQUIRE_CHEATS; - REQUIRE_INLEVEL; + REQUIRE_INLEVEL_OR_REPLAY; if (COM_Argc() != 4) { @@ -615,7 +618,7 @@ void Command_Goto_f(void) const waypoint_t *wayp = K_GetWaypointFromID(id); REQUIRE_CHEATS; - REQUIRE_INLEVEL; + REQUIRE_INLEVEL_OR_REPLAY; if (COM_Argc() != 2) { @@ -639,7 +642,7 @@ void Command_Angle_f(void) const angle_t angle = FixedAngle(FLOAT_TO_FIXED(anglef)); REQUIRE_CHEATS; - REQUIRE_INLEVEL; + REQUIRE_INLEVEL_OR_REPLAY; D_Cheat(consoleplayer, CHEAT_ANGLE, angle); } @@ -661,7 +664,7 @@ void Command_RespawnAt_f(void) void Command_GotoSkybox_f(void) { REQUIRE_CHEATS; - REQUIRE_INLEVEL; + REQUIRE_INLEVEL_OR_REPLAY; mobj_t *skybox = players[consoleplayer].skybox.viewpoint; diff --git a/src/st_stuff.c b/src/st_stuff.c index c02ad0c8e..ab0f45e19 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -452,10 +452,10 @@ void ST_drawDebugInfo(void) { INT32 height = 192; - const UINT8 screen = cv_devmode_screen.value - 1; + const UINT8 screen = min(r_splitscreen, cv_devmode_screen.value - 1); // devmode_screen = 1..4 - stplyr = &players[displayplayers[min(r_splitscreen, screen)]]; + stplyr = &players[displayplayers[screen]]; if (!stplyr->mo) return; @@ -472,11 +472,23 @@ void ST_drawDebugInfo(void) if (cht_debug & DBG_BASIC) { - const fixed_t d = AngleFixed(stplyr->mo->angle); - V_DrawRightAlignedString(320, height - 24, V_MONOSPACE, va("X: %6d", stplyr->mo->x>>FRACBITS)); - V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("Y: %6d", stplyr->mo->y>>FRACBITS)); - V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Z: %6d", stplyr->mo->z>>FRACBITS)); - V_DrawRightAlignedString(320, height, V_MONOSPACE, va("A: %6d", FixedInt(d))); + camera_t *cam = &camera[screen]; + if (stplyr->spectator || cam->freecam) + { + const fixed_t d = AngleFixed(cam->angle); + V_DrawRightAlignedString(320, height - 24, V_MONOSPACE, va("X: %6d", cam->x>>FRACBITS)); + V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("Y: %6d", cam->y>>FRACBITS)); + V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Z: %6d", cam->z>>FRACBITS)); + V_DrawRightAlignedString(320, height, V_MONOSPACE, va("A: %6d", FixedInt(d))); + } + else + { + const fixed_t d = AngleFixed(stplyr->mo->angle); + V_DrawRightAlignedString(320, height - 24, V_MONOSPACE, va("X: %6d", stplyr->mo->x>>FRACBITS)); + V_DrawRightAlignedString(320, height - 16, V_MONOSPACE, va("Y: %6d", stplyr->mo->y>>FRACBITS)); + V_DrawRightAlignedString(320, height - 8, V_MONOSPACE, va("Z: %6d", stplyr->mo->z>>FRACBITS)); + V_DrawRightAlignedString(320, height, V_MONOSPACE, va("A: %6d", FixedInt(d))); + } height -= 40; }