diff --git a/src/d_clisrv.c b/src/d_clisrv.c index d9d686d9c..b3d6b1c6d 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -2739,7 +2739,7 @@ void CL_RemovePlayer(INT32 playernum, kickreason_t reason) LUA_InvalidatePlayer(&players[playernum]); // don't look through someone's view who isn't there - G_ResetViews(); + G_ResetViews(false); K_CheckBumpers(); P_CheckRacers(); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 1657adea4..ab38a093e 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -203,6 +203,8 @@ static void Command_Respawn2(void); static void Command_Respawn3(void); static void Command_Respawn4(void); +static void Command_ReplayMarker(void); + static void Command_Version_f(void); #ifdef UPDATE_ALERT static void Command_ModDetails_f(void); @@ -953,6 +955,8 @@ void D_RegisterServerCommands(void) COM_AddCommand("archivetest", Command_Archivetest_f); #endif + COM_AddCommand("replaymarker", Command_ReplayMarker); + COM_AddCommand("downloads", Command_Downloads_f); COM_AddCommand("kartgiveitem", Command_KartGiveItem_f); @@ -3627,6 +3631,41 @@ static void Got_Pause(UINT8 **cp, INT32 playernum) G_ResetAllDeviceRumbles(); } +static void Command_ReplayMarker(void) +{ + if (gamestate != GS_LEVEL) + { + CONS_Printf(M_GetText("You must be in a level to use this.\n")); + return; + } + if (demo.savemode == DSM_WILLAUTOSAVE) + { + demo.savemode = DSM_NOTSAVING; + CONS_Printf("Replay unmarked.\n"); + } + else + { + demo.savemode = DSM_WILLAUTOSAVE; + + int adjustedleveltime = leveltime - starttime; + + if (adjustedleveltime < 0) + adjustedleveltime = 0; + + char *title = G_BuildMapTitle(gamemap); + + if (title) + { + snprintf(demo.titlename, 64, "%s [%i:%02d/%.5s]", title, G_TicsToMinutes(adjustedleveltime, false), G_TicsToSeconds(adjustedleveltime), modeattacking ? "Record Attack" : connectedservername); + Z_Free(title); + } + else + snprintf(demo.titlename, 64, "[%i:%02d/%.5s]", G_TicsToMinutes(adjustedleveltime, false), G_TicsToSeconds(adjustedleveltime), modeattacking ? "Record Attack" : connectedservername); + + CONS_Printf("Replay will be saved!\n"); + } +} + // Command for stuck characters in netgames, griefing, etc. static void HandleRespawnCommand(UINT8 localplayer) { diff --git a/src/g_demo.c b/src/g_demo.c index 710d42e36..ee0e02364 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -1157,6 +1157,8 @@ void G_ReadDemoExtraData(void) demobuf.p = G_ReadRawExtraData(&extra, demobuf.p, demo.version); p = extra.playernum; + player_t *player = &players[p]; + if (p == DW_END) break; @@ -1181,42 +1183,42 @@ void G_ReadDemoExtraData(void) G_AddPlayer(extra.playernum, extra.playernum); } - players[p].bot = extra.joindata.bot; - if (players[p].bot) + player->bot = extra.joindata.bot; + if (player->bot) { - players[p].botvars.difficulty = extra.joindata.difficulty; - players[p].botvars.diffincrease = extra.joindata.diffincrease; // needed to avoid having to duplicate logic - players[p].botvars.rival = extra.joindata.rival; + player->botvars.difficulty = extra.joindata.difficulty; + player->botvars.diffincrease = extra.joindata.diffincrease; // needed to avoid having to duplicate logic + player->botvars.rival = extra.joindata.rival; } } if (extra.flags & DXD_PLAYSTATE) { switch (extra.playstate) { case DXD_PST_PLAYING: - if (players[p].spectator == true) + if (player->spectator == true) { - if (players[p].bot) + if (player->bot) { - players[p].spectator = false; + player->spectator = false; } else { - players[p].pflags |= PF_WANTSTOJOIN; + player->pflags |= PF_WANTSTOJOIN; } } //CONS_Printf("player %s is despectating on tic %d\n", player_names[p], leveltime); break; case DXD_PST_SPECTATING: - if (players[p].spectator) + if (player->spectator) { - players[p].pflags &= ~PF_WANTSTOJOIN; + player->pflags &= ~PF_WANTSTOJOIN; } else { - if (players[p].mo) + if (player->mo) { - P_DamageMobj(players[p].mo, NULL, NULL, 1, DMG_SPECTATOR); + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_SPECTATOR); } P_SetPlayerSpectator(p); } @@ -1228,7 +1230,7 @@ void G_ReadDemoExtraData(void) break; } - G_ResetViews(); + G_ResetViews(false); // dont reset our freecam pls thx! // maybe these are necessary? K_CheckBumpers(); @@ -1244,11 +1246,11 @@ void G_ReadDemoExtraData(void) // Skin SetPlayerSkin(p, extra.skinname); - if (stricmp(skins[players[p].skin].name, extra.skinname) != 0) + if (stricmp(skins[player->skin].name, extra.skinname) != 0) FindClosestSkinForStats(p, extra.kartspeed, extra.kartweight); - players[p].kartspeed = extra.kartspeed; - players[p].kartweight = extra.kartweight; + player->kartspeed = extra.kartspeed; + player->kartweight = extra.kartweight; } if (extra.flags & DXD_COLOR) { @@ -1256,9 +1258,9 @@ void G_ReadDemoExtraData(void) for (i = 0; i < numskincolors; i++) if (!stricmp(skincolors[i].name, extra.colorname)) // SRB2kart { - players[p].skincolor = i; - if (players[p].mo) - players[p].mo->color = i; + player->skincolor = i; + if (player->mo) + player->mo->color = i; break; } } @@ -1271,16 +1273,16 @@ void G_ReadDemoExtraData(void) for (i = 0; i < numskincolors +2; i++) // +2 because of Match and Opposite if (!stricmp(Followercolor_cons_t[i].strvalue, extra.followercolor)) { - players[p].followercolor = i; + player->followercolor = i; break; } } if (extra.flags & DXD_RESPAWN) { - if (players[p].mo) + if (player->mo) { // Is this how this should work..? - P_DamageMobj(players[p].mo, NULL, NULL, 1, DMG_INSTAKILL); + P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL); } } if (extra.flags & DXD_WEAPONPREF) @@ -2395,7 +2397,7 @@ void G_ConfirmRewind(tic_t rewindtime) displayplayers[2] = olddp3; displayplayers[3] = olddp4; R_ExecuteSetViewSize(); - G_ResetViews(); + G_ResetViews(true); for (i = splitscreen; i >= 0; i--) P_ResetCamera(&players[displayplayers[i]], &camera[i]); @@ -3758,36 +3760,38 @@ void G_DoPlayDemo(char *defdemoname) { demoplayer_t *plr = &header.playerdata[pnum]; UINT8 p = plr->playernum; + player_t *player = &players[p]; + if (!playeringame[displayplayers[0]] || players[displayplayers[0]].spectator) displayplayers[0] = consoleplayer = serverplayer = p; G_AddPlayer(p, p); - players[p].spectator = !!(plr->flags & DEMO_SPECTATOR); + player->spectator = !!(plr->flags & DEMO_SPECTATOR); if (plr->flags & DEMO_KICKSTART) - players[p].pflags |= PF_KICKSTARTACCEL; + player->pflags |= PF_KICKSTARTACCEL; else - players[p].pflags &= ~PF_KICKSTARTACCEL; + player->pflags &= ~PF_KICKSTARTACCEL; if (plr->flags & DEMO_SHRINKME) - players[p].pflags |= PF_SHRINKME; + player->pflags |= PF_SHRINKME; else - players[p].pflags &= ~PF_SHRINKME; + player->pflags &= ~PF_SHRINKME; - K_UpdateShrinkCheat(&players[p]); + K_UpdateShrinkCheat(player); - if ((players[p].bot = !!(plr->flags & DEMO_BOT)) == true) + if ((player->bot = !!(plr->flags & DEMO_BOT)) == true) { - players[p].botvars.difficulty = plr->bot.difficulty; - players[p].botvars.diffincrease = plr->bot.diffincrease; // needed to avoid having to duplicate logic - players[p].botvars.rival = plr->bot.rival; + player->botvars.difficulty = plr->bot.difficulty; + player->botvars.diffincrease = plr->bot.diffincrease; // needed to avoid having to duplicate logic + player->botvars.rival = plr->bot.rival; } // Name strcpy(player_names[p], plr->name); - /*if (players[p].spectator) + /*if (player->spectator) { CONS_Printf("player %s is spectator at start\n", player_names[p]); }*/ @@ -3799,7 +3803,7 @@ void G_DoPlayDemo(char *defdemoname) for (i = 0; i < numskincolors; i++) if (!stricmp(skincolors[i].name, plr->color)) // SRB2kart { - players[p].skincolor = i; + player->skincolor = i; break; } @@ -3810,23 +3814,23 @@ void G_DoPlayDemo(char *defdemoname) for (i = 0; i < numskincolors +2; i++) // +2 because of Match and Opposite if (!stricmp(Followercolor_cons_t[i].strvalue, plr->followercolor)) { - players[p].followercolor = i; + player->followercolor = i; break; } // Score, since Kart uses this to determine where you start on the map - players[p].score = plr->score; + player->score = plr->score; // Power Levels clientpowerlevels[p][gametype == GT_BATTLE ? PWRLV_BATTLE : PWRLV_RACE] = plr->powerlevel; // Kart stats (set later) - if (stricmp(skins[players[p].skin].name, plr->skin) != 0) + if (stricmp(skins[player->skin].name, plr->skin) != 0) FindClosestSkinForStats(p, plr->kartspeed, plr->kartweight); // Followitem - players[p].followitem = plr->followitem; + player->followitem = plr->followitem; } // end of player read (the 0xFF marker) diff --git a/src/g_game.c b/src/g_game.c index 2efc2721a..005bc954e 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2316,11 +2316,16 @@ void G_FixCamera(UINT8 view) // Increment a viewpoint by offset from the current player. A negative value // decrements. // -void G_AdjustView(UINT8 viewnum, INT32 offset, boolean onlyactive) +void G_AdjustViewEx(UINT8 viewnum, INT32 offset, boolean onlyactive, boolean resetfreecam) { INT32 *displayplayerp, oldview; displayplayerp = &displayplayers[viewnum-1]; oldview = (*displayplayerp); + + // turn off the freecam + if (resetfreecam) + camera[viewnum-1].freecam = false; + G_ResetView(viewnum, ( (*displayplayerp) + offset ), onlyactive); // If no other view could be found, go back to what we had. @@ -2333,7 +2338,7 @@ void G_AdjustView(UINT8 viewnum, INT32 offset, boolean onlyactive) // Ensures all viewpoints are valid // Also demotes splitscreen down to one player. // -void G_ResetViews(void) +void G_ResetViews(boolean resetfreecam) { UINT8 splits; UINT8 viewd; @@ -2357,7 +2362,7 @@ void G_ResetViews(void) */ for (viewd = 1; viewd <= splits; ++viewd) { - G_AdjustView(viewd, 0, false); + G_AdjustViewEx(viewd, 0, false, resetfreecam); } } diff --git a/src/g_game.h b/src/g_game.h index 4cebfe969..6a42a0fee 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -226,9 +226,10 @@ INT32 G_FindView(INT32 startview, UINT8 viewnum, boolean onlyactive, boolean rev INT32 G_CountPlayersPotentiallyViewable(boolean active); void G_FixCamera(UINT8 view); -void G_ResetViews(void); +void G_ResetViews(boolean resetfreecam); void G_ResetView(UINT8 viewnum, INT32 playernum, boolean onlyactive); -void G_AdjustView(UINT8 viewnum, INT32 offset, boolean onlyactive); +void G_AdjustViewEx(UINT8 viewnum, INT32 offset, boolean onlyactive, boolean resetfreecam); +#define G_AdjustView(v,o,oa) G_AdjustViewEx(v,o,oa, true) void G_AddPlayer(INT32 playernum, INT32 console); diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index fa0eee598..1a9202f57 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -152,7 +152,8 @@ enum cameraf { camera_momz, camera_pan, camera_pitch, - camera_pnum + camera_pnum, + camera_freecam, }; @@ -174,6 +175,7 @@ static const char *const camera_opt[] = { "pan", "pitch", "pnum", + "freecam", NULL}; enum hudpatch { @@ -332,10 +334,43 @@ static int camera_get(lua_State *L) case camera_pnum: lua_pushinteger(L, camnum); break; + case camera_freecam: + lua_pushboolean(L, cam->freecam); + break; } return 1; } +static int lib_getCamera(lua_State *L) +{ + // No cameras on dedicated + if (dedicated) + return 0; + + if (lua_type(L, 2) == LUA_TNUMBER) + { + int i = lua_tonumber(L, 2); + + if (i < 0 || i > splitscreen) + return 0; + + LUA_PushUserdata(L, &camera[i], META_CAMERA); + return 1; + } + + return 0; +} + +static int lib_lenCamera(lua_State *L) +{ + if (dedicated) + lua_pushinteger(L, 0); + else + lua_pushinteger(L, splitscreen+1); // splitscreen == 0 -> 1 active camera, splitscreen == 1 -> 2 cameras and so on + + return 1; +} + // // lib_draw // @@ -1671,6 +1706,16 @@ int LUA_HudLib(lua_State *L) lua_setfield(L, -2, "__index"); lua_pop(L,1); + lua_newuserdata(L, 0); + lua_createtable(L, 0, 2); + lua_pushcfunction(L, lib_getCamera); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, lib_lenCamera); + lua_setfield(L, -2, "__len"); + lua_setmetatable(L, -2); + lua_setglobal(L, "cameras"); + luaL_register(L, "hud", lib_hud); return 0; } diff --git a/src/r_main.cpp b/src/r_main.cpp index f857dcb2e..2805e54c3 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -1216,7 +1216,8 @@ static void R_SetupAimingFrame(int s) player_t *player = &players[displayplayers[s]]; camera_t *thiscam = &camera[s]; - if (player->awayviewtics) + if (player->awayviewtics && player->awayviewmobj + && thiscam && !thiscam->freecam) // dont force this if we wanna freecam! { newview->aim = player->awayviewaiming; newview->angle = player->awayviewmobj->angle; @@ -1265,10 +1266,10 @@ void R_SetupFrame(int s, boolean skybox) R_SetupAimingFrame(s); - if (player->awayviewtics) + if (player->awayviewtics && player->awayviewmobj // cut-away view stuff + && thiscam && !thiscam->freecam) // dont force this when we wanna freecam! { - // cut-away view stuff - r_viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN + r_viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN whos altview man? I_Assert(r_viewmobj != NULL); newview->x = r_viewmobj->x; @@ -1476,7 +1477,7 @@ static void R_PortalFrame(portal_t *portal) } } -static void Mask_Pre (maskcount_t* m) +static void Mask_Pre(maskcount_t* m) { m->drawsegs[0] = ds_p - drawsegs; m->vissprites[0] = visspritecount; @@ -1486,7 +1487,7 @@ static void Mask_Pre (maskcount_t* m) m->viewsector = viewsector; } -static void Mask_Post (maskcount_t* m) +static void Mask_Post(maskcount_t* m) { m->drawsegs[1] = ds_p - drawsegs; m->vissprites[1] = visspritecount;