diff --git a/src/d_netcmd.c b/src/d_netcmd.c
index 68b8ecfc1ad1ec65d56cd19de46bb62781a9917e..ac1c0da1e19ec536ad6bcd74e5de017de59bee24 100644
--- a/src/d_netcmd.c
+++ b/src/d_netcmd.c
@@ -884,6 +884,8 @@ void D_RegisterClientCommands(void)
 //	CV_RegisterVar(&cv_grid);
 //	CV_RegisterVar(&cv_snapto);
 
+	CV_RegisterVar(&cv_freedemocamera);
+	
 	// add cheat commands
 	COM_AddCommand("noclip", Command_CheatNoClip_f);
 	COM_AddCommand("god", Command_CheatGod_f);
diff --git a/src/p_tick.c b/src/p_tick.c
index 15ec570546c72253ad4ce276b62e4f2f447dba01..05ffefa7a6bc9813882e85561fe9627f2257e4f2 100644
--- a/src/p_tick.c
+++ b/src/p_tick.c
@@ -37,6 +37,7 @@ tic_t leveltime;
 
 // The entries will behave like both the head and tail of the lists.
 thinker_t thlist[NUM_THINKERLISTS];
+consvar_t cv_freedemocamera = {"freedemocamera", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
 
 void Command_Numthinkers_f(void)
 {
@@ -642,8 +643,11 @@ void P_Ticker(boolean run)
 		{
 			player_t* p = &players[consoleplayer];
 			G_ReadDemoTiccmd(&p->cmd, 0);
-			P_ForceLocalAngle(p, p->cmd.angleturn << 16);
-			localaiming = p->aiming;
+			if (!cv_freedemocamera.value)
+			{
+				P_ForceLocalAngle(p, p->cmd.angleturn << 16);
+				localaiming = p->aiming;
+			}
 		}
 
 		LUAh_PreThinkFrame();
diff --git a/src/p_tick.h b/src/p_tick.h
index 1fb88f3f20a33f3319fd29af2634c2dd46a88417..3b04a427aab99d13b2cd989be69af6815ec2b4c6 100644
--- a/src/p_tick.h
+++ b/src/p_tick.h
@@ -19,6 +19,7 @@
 #endif
 
 extern tic_t leveltime;
+extern consvar_t cv_freedemocamera;
 
 // Called by G_Ticker. Carries out all thinking of enemies and players.
 void Command_Numthinkers_f(void);