diff --git a/BondageClub/Screens/MiniGame/MagicBattle/MagicBattle.js b/BondageClub/Screens/MiniGame/MagicBattle/MagicBattle.js
index 7d56d668a6..94bf9db4b0 100644
--- a/BondageClub/Screens/MiniGame/MagicBattle/MagicBattle.js
+++ b/BondageClub/Screens/MiniGame/MagicBattle/MagicBattle.js
@@ -4,6 +4,7 @@ var MagicBattleOpponent = null;
 var MagicBattleReturnFunction = "";
 var MagicBattleDifficulty = 0;
 var MagicBattleVictory = false;
+/** @type Array<number> */
 var MagicBattleAvailSpell = [];
 var MagicBattleOpponentSpell = 0;
 var MagicBattlePlayerAppearance = null;
@@ -12,6 +13,10 @@ var MagicBattleSpellDifficulty = [3, 5, 7, 9, 6, 8, 4, 8];
 
 /**
  * Start a magic battle against an opponent
+ * @param {Character} Opponent
+ * @param {number} Difficulty
+ * @param {string} Background
+ * @param {string} FunctionName
  * @returns {void} - Nothing
  */
 function MagicBattleStart(Opponent, Difficulty, Background, FunctionName) {
@@ -37,6 +42,7 @@ function MagicBattleLoad() {
 
 /**
  * Returns a difficulty factor based on the character nakedness and predicament
+ * @param {Character} C
  * @returns {number} - Difficulty from 0 (full cloth, no restrain) to 10 (naked, fully restrained)
  */
 function MagicBattleGetDifficulty(C) {
@@ -61,7 +67,8 @@ function MagicBattleGetDifficulty(C) {
 
 /**
  * Returns the spells that are available based on opponent (C) clothing and restraints
- * @returns {void} - Nothing
+ * @param {Character} C
+ * @returns {Array<number>} - Nothing
  */
 function MagicBattleGetAvailSpells(C) {
 	if (C == null) return [];
@@ -125,6 +132,7 @@ function MagicBattleClick() {
 
 /**
  * Starts the magic puzzle mini-game for a specific spell (S)
+ * @param {number} S
  * @returns {void} - Nothing
  */
 function MagicBattleSpellStart(S) {
@@ -143,10 +151,12 @@ function MagicBattleSpellStart(S) {
 
 /**
  * Applies the effect of a magic spell (Spell) on a character (C)
+ * @param {Character} C
+ * @param {number} Spell
  * @returns {void} - Nothing
  */
 function MagicSpellEffect(C, Spell) {
-	
+
 	// Strip spell
 	if (Spell == 0) {
 		if ((InventoryGet(C, "Cloth") != null) || (InventoryGet(C, "ClothLower") != null) || (InventoryGet(C, "ClothAccessory") != null) || (InventoryGet(C, "Shoes") != null)) {
@@ -238,5 +248,5 @@ function MagicBattleSpellEnd() {
  * @returns {void} - Nothing
  */
 function MagicBattleKeyDown() {
-	//if (MiniGameCheatKeyDown()) 
+	//if (MiniGameCheatKeyDown())
 }
diff --git a/BondageClub/Screens/Online/ChatCreate/ChatCreate.js b/BondageClub/Screens/Online/ChatCreate/ChatCreate.js
index 70a222f43a..c3544fbfa4 100644
--- a/BondageClub/Screens/Online/ChatCreate/ChatCreate.js
+++ b/BondageClub/Screens/Online/ChatCreate/ChatCreate.js
@@ -19,15 +19,13 @@ var ChatCreateIsHidden = false;
 function ChatCreateLoad() {
 
 	// Resets the LARP game status
-	if ((ChatRoomGame == "LARP") && (Player.Game != null) && (Player.Game.LARP != null) && (Player.Game.LARP.Status != "")) {
-		Player.Game.LARP.Status = "";
-		ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
+	if ((ChatRoomGame == "LARP") && (GameLARPGetStatus() != "")) {
+		GameLARPSetStatus("");
 	}
 
 	// Resets the Magic Battle game status
-	if ((ChatRoomGame == "MagicBattle") && (Player.Game != null) && (Player.Game.MagicBattle != null) && (Player.Game.MagicBattle.Status != "")) {
-		Player.Game.MagicBattle.Status = "";
-		ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
+	if ((ChatRoomGame == "MagicBattle") && (GameMagicBattleGetStatus() != "")) {
+		GameMagicBattleSetStatus("");
 	}
 
 	// If the current background isn't valid, we pick the first one
diff --git a/BondageClub/Screens/Online/Game/OnlineGame.js b/BondageClub/Screens/Online/Game/OnlineGame.js
index cb874590ba..e1637337b1 100644
--- a/BondageClub/Screens/Online/Game/OnlineGame.js
+++ b/BondageClub/Screens/Online/Game/OnlineGame.js
@@ -1,5 +1,6 @@
 "use strict";
-var OnlineGameDictionary = null;
+/** @type string[][] */
+let OnlineGameDictionary = null;
 
 /**
  * Loads the online game dictionary that will be used throughout the game to output messages
@@ -51,8 +52,8 @@ function OnlineGameDictionaryText(KeyWord) {
  * @return {*} Returns the return content of click function of the currently selected game, or false if there is no corresponding game
  */
 function OnlineGameClickCharacter(C) {
-	if ((ChatRoomGame == "LARP") && (GameLARPStatus != "")) return GameLARPCharacterClick(C);
-	if ((ChatRoomGame == "MagicBattle") && (GameMagicBattleStatus != "")) return GameMagicBattleCharacterClick(C);
+	if ((ChatRoomGame == "LARP") && (GameLARPGetStatus() != "")) return GameLARPCharacterClick(C);
+	if ((ChatRoomGame == "MagicBattle") && (GameMagicBattleGetStatus() != "")) return GameMagicBattleCharacterClick(C);
 	return false;
 }
 
@@ -61,8 +62,8 @@ function OnlineGameClickCharacter(C) {
  * @return {*} Returns the return content of click function of the currently selected game, or false if there is no corresponding game
  */
 function OnlineGameClick() {
-	if ((ChatRoomGame == "LARP") && (GameLARPStatus != "")) return GameLARPClickProcess();
-	if ((ChatRoomGame == "MagicBattle") && (GameMagicBattleStatus != "")) return GameMagicBattleClickProcess();
+	if ((ChatRoomGame == "LARP") && (GameLARPGetStatus() != "")) return GameLARPClickProcess();
+	if ((ChatRoomGame == "MagicBattle") && (GameMagicBattleGetStatus() != "")) return GameMagicBattleClickProcess();
 	return false;
 }
 
@@ -83,8 +84,8 @@ function OnlineGameRun() {
  * @returns {boolean} - Returns TRUE if there's no online game that currently blocks changing
  */
 function OnlineGameAllowChange() {
-	if ((ChatRoomGame == "LARP") && (GameLARPStatus != "")) return false;
-	if ((ChatRoomGame == "MagicBattle") && (GameMagicBattleStatus != "")) return false;
+	if ((ChatRoomGame == "LARP") && (GameLARPGetStatus() != "")) return false;
+	if ((ChatRoomGame == "MagicBattle") && (GameMagicBattleGetStatus() != "")) return false;
 	return true;
 }
 
@@ -93,8 +94,8 @@ function OnlineGameAllowChange() {
  * @returns {boolean} - Returns TRUE if the online game allows you to block items
  */
 function OnlineGameAllowBlockItems() {
-	if ((ChatRoomGame == "LARP") && (GameLARPStatus != "")) return false;
-	if ((ChatRoomGame == "MagicBattle") && (GameMagicBattleStatus != "")) return false;
+	if ((ChatRoomGame == "LARP") && (GameLARPGetStatus() != "")) return false;
+	if ((ChatRoomGame == "MagicBattle") && (GameMagicBattleGetStatus() != "")) return false;
 	return true;
 }
 
@@ -103,22 +104,8 @@ function OnlineGameAllowBlockItems() {
  * @returns {void} - Nothing
  */
 function OnlineGameLoadStatus() {
-	if (ChatRoomGame == "LARP") {
-		for (let C = 0; C < ChatRoomCharacter.length; C++)
-			if ((ChatRoomData.Admin.indexOf(ChatRoomCharacter[C].MemberNumber) >= 0) && (ChatRoomCharacter[C].Game != null) && (ChatRoomCharacter[C].Game.LARP != null) && (ChatRoomCharacter[C].Game.LARP.Status != "")) {
-				GameLARPStatus = ChatRoomCharacter[C].Game.LARP.Status;
-				return;
-			}
-		GameLARPReset();
-	}
-	if (ChatRoomGame == "MagicBattle") {
-		for (let C = 0; C < ChatRoomCharacter.length; C++)
-			if ((ChatRoomData.Admin.indexOf(ChatRoomCharacter[C].MemberNumber) >= 0) && (ChatRoomCharacter[C].Game != null) && (ChatRoomCharacter[C].Game.MagicBattle != null) && (ChatRoomCharacter[C].Game.MagicBattle.Status != "")) {
-				GameMagicBattleStatus = ChatRoomCharacter[C].Game.MagicBattle.Status;
-				return;
-			}
-		GameMagicBattleReset();
-	}
+	if (ChatRoomGame == "LARP") GameLARPLoadStatus();
+	if (ChatRoomGame == "MagicBattle") GameMagicBattleLoadStatus();
 }
 
 /**
@@ -151,70 +138,7 @@ function OnlineGameCharacterInChatRoom(MemberNumber) {
  * @returns {void} - Nothing
  */
 function OnlineGameDrawCharacter(C, X, Y, Zoom) {
-
-	// GGTS Draws the level, the number of strikes and a progress bar, level 6 shows the time in a gold frame
-	if ((CurrentModule == "Online") && (CurrentScreen == "ChatRoom") && (ChatRoomGame == "GGTS") && (ChatRoomSpace === "Asylum")) {
-		let Level = AsylumGGTSGetLevel(C);
-		if ((Level > 0) && (C.Game != null) && (C.Game.GGTS != null)) {
-			if (C.Game.GGTS.Strike >= 1) DrawImageZoomCanvas("Screens/Room/AsylumGGTS/Strike" + C.Game.GGTS.Strike.toString() + ".png", MainCanvas, 0, 0, 100, 50, X + 50 * Zoom, Y + 800 * Zoom, 100 * Zoom, 50 * Zoom);
-			MainCanvas.font = CommonGetFont(Math.round(36 * Zoom));
-			let Progress = Math.floor(C.Game.GGTS.Time / AsylumGGTSLevelTime[Level] * 100);
-			if (C.Game.GGTS.Strike >= 3) Progress = 0;
-			if ((Level >= 6) || (Progress >= 100)) DrawEmptyRect(X + 50 * Zoom, Y + 860 * Zoom, 100 * Zoom, 40 * Zoom, "Black");
-			if (Level >= 6) DrawRect(X + 52 * Zoom, Y + 862 * Zoom, 96 * Zoom, 36 * Zoom, "#FFD700");
-			else if (Progress >= 100) DrawRect(X + 50 * Zoom, Y + 860 * Zoom, 100 * Zoom, 40 * Zoom, "White");
-			else DrawProgressBar(X + 50 * Zoom, Y + 860 * Zoom, 100 * Zoom, 40 * Zoom, Progress);
-			if (Level >= 6) DrawText(Math.floor(C.Game.GGTS.Time / 60000).toString(), X + 100 * Zoom, Y + 881 * Zoom, "Black", "White");
-			else if (Progress >= 50) DrawText(Level.toString(), X + 100 * Zoom, Y + 881 * Zoom, "Black", "White");
-			else DrawText(Level.toString(), X + 101 * Zoom, Y + 882 * Zoom, "White", "Black");
-			if (C.Game.GGTS.Rule != null)
-				for (let R = 0; R < C.Game.GGTS.Rule.length; R++)
-					DrawImageZoomCanvas("Screens/Room/AsylumGGTS/Rule" + C.Game.GGTS.Rule[R] + ".png", MainCanvas, 0, 0, 33, 33, X + 50 * Zoom + R * 33 * Zoom, Y + 902 * Zoom, 33 * Zoom, 33 * Zoom);
-			if ((C.ID == 0) && (AsylumGGTSTimer > 0) && (AsylumGGTSTimer > CommonTime()) && (C.Game.GGTS.Strike < 3)) {
-				let ForeColor = (AsylumGGTSTask == null) ? "Black" : "White";
-				let BackColor = (ForeColor == "White") ? "Black" : "White";
-				if ((BackColor == "Black") && (Math.round((AsylumGGTSTimer - CommonTime()) / 1000) <= 10)) BackColor = "Red";
-				DrawEmptyRect(X + 350 * Zoom, Y + 860 * Zoom, 100 * Zoom, 40 * Zoom, ForeColor, 2);
-				DrawRect(X + 352 * Zoom, Y + 862 * Zoom, 96 * Zoom, 36 * Zoom, BackColor);
-				DrawText(Math.round((AsylumGGTSTimer - CommonTime()) / 1000).toString(), X + 399 * Zoom, Y + 882 * Zoom, ForeColor, "Silver");
-			}
-			MainCanvas.font = CommonGetFont(36);
-		}
-	}
-
-	// LARP draws the timer if needed and the icon linked to team and class
-	if ((CurrentModule == "Online") && (CurrentScreen == "ChatRoom") && (ChatRoomGame == "LARP")) {
-		GameLARPDrawIcon(C, X + 70 * Zoom, Y + 800 * Zoom, 0.6 * Zoom);
-		if ((GameLARPPlayer.length > 0) && (C.MemberNumber == GameLARPPlayer[GameLARPTurnPosition].MemberNumber) && (GameLARPStatus == "Running") && (GameLARPTurnFocusCharacter == null)) {
-			MainCanvas.font = CommonGetFont(72);
-			var Time = Math.ceil((GameLARPTurnTimer - TimerGetTime()) / 1000);
-			DrawText(((Time < 0) || (Time > GameLARPTimerDelay[GameLARPTimerDelay.length - 1])) ? OnlineGameDictionaryText("TimerNA") : Time.toString(), X + 250 * Zoom, Y + 830 * Zoom, "Red", "Black");
-			MainCanvas.font = CommonGetFont(36);
-		}
-	}
-
-	// Magic battle draws the timer and the spell buttons
-	if ((CurrentModule == "Online") && (CurrentScreen == "ChatRoom") && (ChatRoomGame == "MagicBattle")) {
-		GameMagicBattleDrawIcon(C, X + 70 * Zoom, Y + 800 * Zoom, 0.6 * Zoom);
-		if (Player.CanTalk() && (GameMagicBattleStatus == "Running")) {
-			if (C.MemberNumber == Player.MemberNumber) {
-				MainCanvas.font = CommonGetFont(72);
-				let Time = Math.ceil((GameMagicBattleTurnTimer - TimerGetTime()) / 1000);
-				let Color = "#00FF00";
-				if (Time <= 15) Color = "#FFFF00";
-				if (Time <= 6) Color = "#FF0000";
-				DrawText(((Time < 0) || (Time > GameMagicBattleTimerDelay)) ? OnlineGameDictionaryText("TimerNA") : Time.toString(), X + 250 * Zoom, Y + 830 * Zoom, Color, "Black");
-				MainCanvas.font = CommonGetFont(36);
-			}
-			if ((GameMagicBattleFocusCharacter != null) && (C.MemberNumber == GameMagicBattleFocusCharacter.MemberNumber) && (GameMagicBattleStatus == "Running")) {
-				GameMagicBattleButton = [];
-				for (let S = 0; S < MagicBattleAvailSpell.length; S++) {
-					let B = { X: X + 50 * Zoom, Y: Y + (400 + (S * 100)) * Zoom, W: 400 * Zoom, H: 60 * Zoom };
-					GameMagicBattleButton.push(B);
-					DrawButton(B.X, B.Y, B.W, B.H, OnlineGameDictionaryText("Spell" + MagicBattleAvailSpell[S].toString() + "Name"), "White");
-				}
-			}
-		}
-	}
-
+	if (ChatRoomGame === "GGTS") AsylumGGTSDrawCharacter(C, X, Y, Zoom);
+	if (ChatRoomGame === "LARP") GameLARPDrawCharacter(C, X, Y, Zoom);
+	if (ChatRoomGame === "MagicBattle") GameMagicBattleDrawCharacter(C, X, Y, Zoom);
 }
diff --git a/BondageClub/Screens/Online/GameLARP/GameLARP.js b/BondageClub/Screens/Online/GameLARP/GameLARP.js
index a9c0f878b9..63647d3aa4 100644
--- a/BondageClub/Screens/Online/GameLARP/GameLARP.js
+++ b/BondageClub/Screens/Online/GameLARP/GameLARP.js
@@ -36,7 +36,6 @@ var GameLARPTeamList = ["None", "Red", "Green", "Blue", "Yellow", "Cyan", "Purpl
 var GameLARPTimerDelay = [20, 60];
 var GameLARPEntryClass = "";
 var GameLARPEntryTeam = "";
-var GameLARPStatus = "";
 var GameLARPProgress = [];
 var GameLARPPlayer = [];
 var GameLARPOption = [];
@@ -51,13 +50,40 @@ var GameLARPTurnTimerDelay = GameLARPTimerDelay[0];
 var GameLARPTurnFocusCharacter = null;
 var GameLARPTurnFocusGroup = null;
 
+/**
+ * Gets the current state of LARP.
+ * @returns {OnlineGameStatus}
+ */
+function GameLARPGetStatus() {
+	if (Player.Game && Player.Game.LARP && ["", "Running"].includes(Player.Game.LARP.Status))
+		return Player.Game.LARP.Status;
+	return "";
+}
+
+/**
+ * Set the current state of LARP.
+ * @param {OnlineGameStatus} s
+ * @returns {void}
+ */
+function GameLARPSetStatus(s) {
+	if (!["", "Running"].includes(s))
+		return;
+
+	if (Player.Game == null || Player.Game.LARP == null)
+		GameLARPLoad();
+
+	/* @ts-ignore */
+	Player.Game.LARP.Status = s;
+	ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
+}
+
 /**
  * Checks if the character is an admin or the LARP admin while the game is going.
  * @param {Character} C - Character to check for
  * @returns {boolean} -  Returns TRUE if that character is an admin/the game administrator
  */
 function GameLARPIsAdmin(C) {
-	if (GameLARPStatus == "")
+	if (GameLARPGetStatus() == "")
 		return (ChatRoomData.Admin.indexOf(C.MemberNumber) >= 0);
 	else
 		return (GameLARPTurnAdmin == C.MemberNumber);
@@ -82,13 +108,18 @@ function GameLARPDrawIcon(C, X, Y, Zoom) {
  */
 function GameLARPLoad() {
 	if (Player.Game == null) Player.Game = {};
-	if (Player.Game.LARP == null) Player.Game.LARP = {};
-	if (Player.Game.LARP.Class == null) Player.Game.LARP.Class = GameLARPClass[0].Name;
-	if (Player.Game.LARP.Team == null) Player.Game.LARP.Team = GameLARPTeamList[0];
-	if (Player.Game.LARP.TimerDelay == null) Player.Game.LARP.TimerDelay = GameLARPTimerDelay[0];
+	let game = Player.Game.LARP;
+	Player.Game.LARP = {
+		Class: (game && typeof game.Class !== undefined ? game.Class : GameLARPClass[0].Name),
+		Team: (game && typeof game.Team !== undefined ? game.Team : GameLARPTeamList[0]),
+		TimerDelay: (game && typeof game.TimerDelay !== undefined ? game.TimerDelay : GameLARPTimerDelay[0]),
+		Status: "",
+		Level: (game && typeof game.Level != undefined ? game.Level : []),
+	};
+
 	GameLARPEntryClass = Player.Game.LARP.Class;
 	GameLARPEntryTeam = Player.Game.LARP.Team;
-	if (GameLARPStatus == "") GameLARPProgress = [];
+	if (GameLARPGetStatus() == "") GameLARPProgress = [];
 }
 
 /**
@@ -103,15 +134,15 @@ function GameLARPRun() {
 	DrawText(TextGet("Title"), 550, 125, "Black", "Gray");
 	DrawText(TextGet("SelectClass"), 550, 225, "Black", "Gray");
 	DrawText(TextGet("SelectTeam"), 550, 425, "Black", "Gray");
-	if (GameLARPStatus != "") DrawText(TextGet("Class" + Player.Game.LARP.Class), 900, 225, "Black", "Gray");
+	if (GameLARPGetStatus() != "") DrawText(TextGet("Class" + Player.Game.LARP.Class), 900, 225, "Black", "Gray");
 	DrawText(TextGet("LevelProgress"), 550, 325, "Black", "Gray");
 	DrawText(GameLARPGetClassLevel(Player.Game.LARP) + " (" + Math.floor(GameLARPGetClassProgress(Player.Game.LARP) / 10).toString() + "%)", 900, 325, "Black", "Gray");
-	if (GameLARPStatus != "") DrawText(TextGet("Color" + Player.Game.LARP.Team), 900, 425, "Black", "Gray");
-	DrawText(TextGet((GameLARPStatus == "") ? "StartCondition" : "RunningGame"), 550, 525, "Black", "Gray");
+	if (GameLARPGetStatus() != "") DrawText(TextGet("Color" + Player.Game.LARP.Team), 900, 425, "Black", "Gray");
+	DrawText(TextGet((GameLARPGetStatus() == "") ? "StartCondition" : "RunningGame"), 550, 525, "Black", "Gray");
 	MainCanvas.textAlign = "center";
 	DrawButton(1815, 75, 90, 90, "", "White", "Icons/Exit.png");
-	if (GameLARPStatus == "") DrawBackNextButton(900, 193, 400, 64, TextGet("Class" + Player.Game.LARP.Class), "White", "", () => "", () => "");
-	if (GameLARPStatus == "") DrawBackNextButton(900, 393, 400, 64, TextGet("Color" + Player.Game.LARP.Team), "White", "", () => "", () => "");
+	if (GameLARPGetStatus() == "") DrawBackNextButton(900, 193, 400, 64, TextGet("Class" + Player.Game.LARP.Class), "White", "", () => "", () => "");
+	if (GameLARPGetStatus() == "") DrawBackNextButton(900, 393, 400, 64, TextGet("Color" + Player.Game.LARP.Team), "White", "", () => "", () => "");
 	GameLARPDrawIcon(Player, 1400, 225, 2);
 	if (GameLARPCanLaunchGame()) DrawBackNextButton(550, 600, 400, 65, TextGet("TimerDelay" + Player.Game.LARP.TimerDelay), "White", "", () => "", () => "");
 	if (GameLARPCanLaunchGame()) DrawButton(1050, 600, 400, 65, TextGet("StartGame"), "White");
@@ -125,13 +156,13 @@ function GameLARPRun() {
 function GameLARPRunProcess() {
 
 	// If the player is an admin, she can make player skip their turns
-	if ((GameLARPStatus == "Running") && (TimerGetTime() > GameLARPTurnTimer) && GameLARPIsAdmin(Player)) {
+	if ((GameLARPGetStatus() == "Running") && (TimerGetTime() > GameLARPTurnTimer) && GameLARPIsAdmin(Player)) {
 		GameLARPTurnTimer = TimerGetTime() + (GameLARPTurnTimerDelay * 1000);
 		ServerSend("ChatRoomGame", { GameProgress: "Skip" });
 	}
 
 	// Clears the focused character if it's not the player turn
-	if ((GameLARPTurnFocusCharacter != null) && ((GameLARPStatus != "Running") || (GameLARPPlayer[GameLARPTurnPosition].ID != 0))) GameLARPTurnFocusCharacter = null;
+	if ((GameLARPTurnFocusCharacter != null) && ((GameLARPGetStatus() != "Running") || (GameLARPPlayer[GameLARPTurnPosition].ID != 0))) GameLARPTurnFocusCharacter = null;
 
 	// If we must show the focused character and available abilities
 	if (GameLARPTurnFocusCharacter != null) {
@@ -281,8 +312,7 @@ function GameLARPStartProcess() {
 
 	// Changes the game status and exits
 	ServerSend("ChatRoomGame", { GameProgress: "Start" });
-	Player.Game.LARP.Status = "Running";
-	ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
+	GameLARPSetStatus("Running");
 	ChatRoomCharacterUpdate(Player);
 }
 
@@ -296,7 +326,7 @@ function GameLARPClick() {
 	if (MouseIn(1815, 75, 90, 90)) GameLARPExit();
 
 	// When the user selects a new class
-	if (MouseIn(900, 193, 400, 64) && (GameLARPStatus == "")) {
+	if (MouseIn(900, 193, 400, 64) && (GameLARPGetStatus() == "")) {
 		var Index = 0;
 		for (let I = 0; I < GameLARPClass.length; I++)
 			if (GameLARPClass[I].Name == Player.Game.LARP.Class)
@@ -307,7 +337,7 @@ function GameLARPClick() {
 	}
 
 	// When the user selects a new team
-	if (MouseIn(900, 393, 400, 64) && (GameLARPStatus == "")) {
+	if (MouseIn(900, 393, 400, 64) && (GameLARPGetStatus() == "")) {
 		if (MouseX <= 1100) Player.Game.LARP.Team = (GameLARPTeamList.indexOf(Player.Game.LARP.Team) <= 0) ? GameLARPTeamList[GameLARPTeamList.length - 1] : GameLARPTeamList[GameLARPTeamList.indexOf(Player.Game.LARP.Team) - 1];
 		else Player.Game.LARP.Team = (GameLARPTeamList.indexOf(Player.Game.LARP.Team) >= GameLARPTeamList.length - 1) ? GameLARPTeamList[0] : GameLARPTeamList[GameLARPTeamList.indexOf(Player.Game.LARP.Team) + 1];
 	}
@@ -348,7 +378,7 @@ function GameLARPClick() {
 function GameLARPExit() {
 
 	// When the game isn't running, we allow to change the class or team
-	if (GameLARPStatus == "") {
+	if (GameLARPGetStatus() == "") {
 
 		// Notices everyone in the room of the change, if there is any
 		if (GameLARPEntryClass != Player.Game.LARP.Class || GameLARPEntryTeam != Player.Game.LARP.Team) {
@@ -377,7 +407,7 @@ function GameLARPExit() {
 function GameLARPCanLaunchGame() {
 	if (Player.Game.LARP.Class == null || Player.Game.LARP.Class == "") return false;
 	if (Player.Game.LARP.Team == null || Player.Game.LARP.Team == "None") return false;
-	if (GameLARPStatus != "") return false;
+	if (GameLARPGetStatus() != "") return false;
 	if (!GameLARPIsAdmin(Player)) return false;
 	var Team = "";
 	for (let C = 0; C < ChatRoomCharacter.length; C++)
@@ -726,7 +756,7 @@ function GameLARPProcessAction(Action, ItemName, Source, Target, RNG) {
 function GameLARPCharacterClick(C) {
 
 	// If it's the player turn, we allow clicking on a character to get the abilities menu
-	if ((GameLARPStatus == "Running") && (GameLARPPlayer[GameLARPTurnPosition].ID == 0) && (C.Game != null) && (C.Game.LARP != null) && (C.Game.LARP.Team != null) && (C.Game.LARP.Team != "") && (C.Game.LARP.Team != "None")) {
+	if ((GameLARPGetStatus() == "Running") && (GameLARPPlayer[GameLARPTurnPosition].ID == 0) && (C.Game != null) && (C.Game.LARP != null) && (C.Game.LARP.Team != null) && (C.Game.LARP.Team != "") && (C.Game.LARP.Team != "None")) {
 		GameLARPTurnFocusCharacter = C;
 		GameLARPTurnFocusGroup = null;
 		GameLARPOption = GameLARPBuildOption(Player, GameLARPTurnFocusCharacter);
@@ -951,7 +981,7 @@ function GameLARPProcess(P) {
 
 		// The administrator can start the LARP game, he becomes the turn admin in the process
 		if ((ChatRoomData.Admin.indexOf(P.Sender) >= 0) && (P.Data.GameProgress == "Start")) {
-			GameLARPStatus = "Running";
+			GameLARPSetStatus("Running");
 			GameLARPTurnAdmin = P.Sender;
 			GameLARPTurnPosition = -1;
 			GameLARPTurnAscending = true;
@@ -965,13 +995,13 @@ function GameLARPProcess(P) {
 		}
 
 		// The turn administrator can skip turns after the delay has ran out
-		if ((GameLARPStatus == "Running") && (GameLARPTurnAdmin == P.Sender) && (P.Data.GameProgress == "Skip")) {
+		if ((GameLARPGetStatus() == "Running") && (GameLARPTurnAdmin == P.Sender) && (P.Data.GameProgress == "Skip")) {
 			GameLARPProgress.push({ Sender: P.Sender, Time: CurrentTime, RNG: P.RNG, Data: P.Data });
 			if (GameLARPContinue()) GameLARPNewTurn("TurnSkip");
 		}
 
 		// The current turn player can trigger an action
-		if ((GameLARPStatus == "Running") && (GameLARPPlayer[GameLARPTurnPosition].MemberNumber == P.Sender) && (P.Data.GameProgress == "Action") && (P.Data.Action != null) && (P.Data.Target != null)) {
+		if ((GameLARPGetStatus() == "Running") && (GameLARPPlayer[GameLARPTurnPosition].MemberNumber == P.Sender) && (P.Data.GameProgress == "Action") && (P.Data.Action != null) && (P.Data.Target != null)) {
 
 			// Before we process it, we make sure the action is valid by checking all possible options
 			var Source = GameLARPGetPlayer(P.Sender);
@@ -997,9 +1027,40 @@ function GameLARPProcess(P) {
  * @returns {void} - Nothing
  */
 function GameLARPReset() {
-	GameLARPStatus = "";
-	if ((Player.Game != null) && (Player.Game.LARP != null) && (Player.Game.LARP.Status != null) && (Player.Game.LARP.Status != "")) {
-		Player.Game.LARP.Status = "";
-		ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
+	GameLARPSetStatus("");
+}
+
+/**
+ * Ensure all character's MagicBattle game status are the same
+ */
+function GameLARPLoadStatus() {
+	for (let C = 0; C < ChatRoomCharacter.length; C++)
+		if ((ChatRoomData.Admin.indexOf(ChatRoomCharacter[C].MemberNumber) >= 0) && (ChatRoomCharacter[C].Game != null) && (ChatRoomCharacter[C].Game.LARP != null) && (ChatRoomCharacter[C].Game.LARP.Status != "")) {
+			GameLARPSetStatus(ChatRoomCharacter[C].Game.LARP.Status);
+			return;
+		}
+	GameLARPReset();
+}
+
+
+/**
+ * Draws the online game images/text needed on the characters
+ * @param {Character} C - Character to draw the info for
+ * @param {number} X - Position of the character the X axis
+ * @param {number} Y - Position of the character the Y axis
+ * @param {number} Zoom - Amount of zoom the character has (Height)
+ * @returns {void} - Nothing
+ */
+function GameLARPDrawCharacter(C, X, Y, Zoom) {
+
+	// LARP draws the timer if needed and the icon linked to team and class
+	if ((CurrentModule == "Online") && (CurrentScreen == "ChatRoom")) {
+		GameLARPDrawIcon(C, X + 70 * Zoom, Y + 800 * Zoom, 0.6 * Zoom);
+		if ((GameLARPPlayer.length > 0) && (C.MemberNumber == GameLARPPlayer[GameLARPTurnPosition].MemberNumber) && (GameLARPGetStatus() == "Running") && (GameLARPTurnFocusCharacter == null)) {
+			MainCanvas.font = CommonGetFont(72);
+			var Time = Math.ceil((GameLARPTurnTimer - TimerGetTime()) / 1000);
+			DrawText(((Time < 0) || (Time > GameLARPTimerDelay[GameLARPTimerDelay.length - 1])) ? OnlineGameDictionaryText("TimerNA") : Time.toString(), X + 250 * Zoom, Y + 830 * Zoom, "Red", "Black");
+			MainCanvas.font = CommonGetFont(36);
+		}
 	}
 }
diff --git a/BondageClub/Screens/Online/GameMagicBattle/GameMagicBattle.js b/BondageClub/Screens/Online/GameMagicBattle/GameMagicBattle.js
index aa860421d0..b4e0718a94 100644
--- a/BondageClub/Screens/Online/GameMagicBattle/GameMagicBattle.js
+++ b/BondageClub/Screens/Online/GameMagicBattle/GameMagicBattle.js
@@ -1,7 +1,6 @@
 "use strict";
 var GameMagicBattleBackground = "Sheet";
 var GameMagicBattleTimerDelay = 30;
-var GameMagicBattleStatus = "";
 var GameMagicBattlePlayer = [];
 var GameMagicBattleAction = "";
 var GameMagicBattleTurnAdmin = null;
@@ -11,6 +10,33 @@ var GameMagicBattleFocusCharacter = null;
 var GameMagicBattleLog = [];
 var GameMagicBattleButton = [];
 
+/**
+ * Gets the current state of LARP.
+ * @returns {OnlineGameStatus}
+ */
+function GameMagicBattleGetStatus() {
+	if (Player.Game && Player.Game.MagicBattle && ["", "Running"].includes(Player.Game.MagicBattle.Status))
+		return Player.Game.MagicBattle.Status;
+	return "";
+}
+
+/**
+ * Set the current state of LARP.
+ * @param {OnlineGameStatus} s
+ * @returns {void}
+ */
+function GameMagicBattleSetStatus(s) {
+	if (!["", "Running"].includes(s))
+		return;
+
+	if (Player.Game == null || Player.Game.MagicBattle == null)
+		GameMagicBattleLoad();
+
+	// @ts-ignore
+	Player.Game.MagicBattle.Status = s;
+	ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
+}
+
 /**
  * Checks if the character is an admin while the game is going.
  * @param {Character} C - Character to check for
@@ -39,9 +65,12 @@ function GameMagicBattleDrawIcon(C, X, Y, Zoom) {
  */
 function GameMagicBattleLoad() {
 	if (Player.Game == null) Player.Game = {};
-	if (Player.Game.MagicBattle == null) Player.Game.MagicBattle = {};
-	if (Player.Game.MagicBattle.House == null) Player.Game.MagicBattle.House = "NotPlaying";
-	if (Player.Game.MagicBattle.TeamType != "FreeForAll") Player.Game.MagicBattle.TeamType = "House";
+	let game = Player.Game.MagicBattle;
+	Player.Game.MagicBattle = {
+		Status: "",
+		House: (game && typeof game.House !== undefined ? game.House : "NotPlaying"),
+		TeamType: (game && typeof game.TeamType !== undefined ? game.TeamType : "House"),
+	};
 }
 
 /**
@@ -51,19 +80,19 @@ function GameMagicBattleLoad() {
 function GameMagicBattleGetTeamType() {
 
 	// If the game is running, we return the setup from the game admin
-	if ((GameMagicBattleStatus == "Running") && (GameMagicBattleTurnAdmin != null))
+	if ((GameMagicBattleGetStatus() == "Running") && (GameMagicBattleTurnAdmin != null))
 		for (let C = 0; C < GameMagicBattlePlayer.length; C++)
 			if (GameMagicBattlePlayer[C].MemberNumber == GameMagicBattleTurnAdmin)
 				if ((GameMagicBattlePlayer[C].Game != null) && (GameMagicBattlePlayer[C].Game.MagicBattle != null) && (GameMagicBattlePlayer[C].Game.MagicBattle.TeamType != null))
 					return GameMagicBattlePlayer[C].Game.MagicBattle.TeamType;
 
 	// When the game isn't running, the player team type is returned if admin
-	if ((GameMagicBattleStatus == "") && GameMagicBattleIsAdmin(Player))
+	if ((GameMagicBattleGetStatus() == "") && GameMagicBattleIsAdmin(Player))
 		if ((Player.Game != null) && (Player.Game.MagicBattle != null) && (Player.Game.MagicBattle.TeamType != null))
 			return Player.Game.MagicBattle.TeamType;
 
 	// When the game isn't running, the first admin team type is returned
-	if ((GameMagicBattleStatus == "") && !GameMagicBattleIsAdmin(Player))
+	if ((GameMagicBattleGetStatus() == "") && !GameMagicBattleIsAdmin(Player))
 		for (let C = 0; C < ChatRoomCharacter.length; C++)
 			if (GameMagicBattleIsAdmin(ChatRoomCharacter[C]))
 				if ((ChatRoomCharacter[C].Game != null) && (ChatRoomCharacter[C].Game.MagicBattle != null) && (ChatRoomCharacter[C].Game.MagicBattle.TeamType != null))
@@ -84,19 +113,19 @@ function GameMagicBattleRun() {
 	let TeamType = GameMagicBattleGetTeamType();
 	DrawCharacter(Player, 50, 50, 0.9);
 	DrawText(TextGet("Title"), 1200, 125, "Black", "Gray");
-	if (GameMagicBattleStatus == "") DrawBackNextButton(900, 218, 600, 64, TextGet("PlayType" + Player.Game.MagicBattle.House), "White", "", () => "", () => "");
+	if (GameMagicBattleGetStatus() == "") DrawBackNextButton(900, 218, 600, 64, TextGet("PlayType" + Player.Game.MagicBattle.House), "White", "", () => "", () => "");
 	else DrawText(TextGet("PlayType" + Player.Game.MagicBattle.House), 1200, 250, "Black", "Gray");
-	if ((GameMagicBattleStatus == "") && GameMagicBattleIsAdmin(Player)) DrawBackNextButton(900, 343, 600, 64, TextGet("TeamType") + " " + TextGet(TeamType), "White", "", () => "", () => "");
+	if ((GameMagicBattleGetStatus() == "") && GameMagicBattleIsAdmin(Player)) DrawBackNextButton(900, 343, 600, 64, TextGet("TeamType") + " " + TextGet(TeamType), "White", "", () => "", () => "");
 	else DrawText(TextGet("TeamType") + " " + TextGet(TeamType), 1200, 375, "Black", "Gray");
-	if (GameMagicBattleStatus == "") DrawText(TextGet("StartCondition" + TeamType), 1200, 500, "Black", "Gray");
+	if (GameMagicBattleGetStatus() == "") DrawText(TextGet("StartCondition" + TeamType), 1200, 500, "Black", "Gray");
 	else DrawText(TextGet("RunningGame"), 1200, 500, "Black", "Gray");
 	if (GameMagicBattleCanLaunchGame()) DrawButton(1000, 600, 400, 65, TextGet("StartGame"), "White");
-	if (GameMagicBattleIsAdmin(Player) && (GameMagicBattleStatus != "")) DrawButton(1000, 600, 400, 65, TextGet("StopGame"), "White");
+	if (GameMagicBattleIsAdmin(Player) && (GameMagicBattleGetStatus() != "")) DrawButton(1000, 600, 400, 65, TextGet("StopGame"), "White");
 	GameMagicBattleDrawIcon(Player, 600, 210, 2);
 
 	// Draw the right side buttons
 	DrawButton(1815, 75, 90, 90, "", "White", "Icons/Exit.png");
-	if ((GameMagicBattleStatus == "") && (Player.Game.MagicBattle.House.indexOf("House") == 0) && Player.CanChange()) DrawButton(1815, 190, 90, 90, "", "White", "Icons/Wardrobe.png");
+	if ((GameMagicBattleGetStatus() == "") && (Player.Game.MagicBattle.House.indexOf("House") == 0) && Player.CanChange()) DrawButton(1815, 190, 90, 90, "", "White", "Icons/Wardrobe.png");
 
 }
 
@@ -107,7 +136,7 @@ function GameMagicBattleRun() {
 function GameMagicBattleRunProcess() {
 
 	// If the player is the game admin, she sends the 30 seconds timer tick to everyone
-	if ((GameMagicBattleStatus == "Running") && (TimerGetTime() > GameMagicBattleTurnTimer) && (Player.MemberNumber == GameMagicBattleTurnAdmin)) {
+	if ((GameMagicBattleGetStatus() == "Running") && (TimerGetTime() > GameMagicBattleTurnTimer) && (Player.MemberNumber == GameMagicBattleTurnAdmin)) {
 		GameMagicBattleTurnTimer = TimerGetTime() + (GameMagicBattleTimerDelay * 1000);
 		ServerSend("ChatRoomGame", { GameProgress: "Next" });
 	}
@@ -138,7 +167,7 @@ function GameMagicBattleClickProcess() {
 
 /**
  * When the magic puzzle ends, we go back to the chat room
- * @returns {boolean} - Returns TRUE if the click was handled by this online click handler
+ * @returns {void}
  */
 function GameMagicBattlePuzzleEnd() {
 	ServerSend("ChatRoomGame", { GameProgress: "Action", Action: (MiniGameVictory ? "SpellSuccess" : "SpellFail"), Spell: MagicPuzzleSpell, Time: MagicPuzzleFinish - MagicPuzzleStart, Target: GameMagicBattleFocusCharacter.MemberNumber });
@@ -155,8 +184,7 @@ function GameMagicBattlePuzzleEnd() {
  */
 function GameMagicBattleStartProcess() {
 
-	// Gives a delay in seconds, based on the player preference, returns to the chat screen
-	CommonSetScreen("Online", "ChatRoom");
+	// Gives a delay in seconds, based on the player preference
 	GameMagicBattleTurnTimer = TimerGetTime() + (GameMagicBattleTimerDelay * 1000);
 
 	// Notices everyone in the room that the game starts
@@ -166,9 +194,7 @@ function GameMagicBattleStartProcess() {
 
 	// Changes the game status and exits
 	ServerSend("ChatRoomGame", { GameProgress: "Start" });
-	Player.Game.MagicBattle.Status = "Running";
-	ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
-
+	GameMagicBattleSetStatus("Running");
 }
 
 /**
@@ -178,14 +204,18 @@ function GameMagicBattleStartProcess() {
 function GameMagicBattleClick() {
 
 	// When the user exits or wants to change clothes
-	if (MouseIn(1815, 75, 90, 90)) GameMagicBattleExit();
-	if (MouseIn(1815, 190, 90, 90) && (GameMagicBattleStatus == "") && (Player.Game.MagicBattle.House.indexOf("House") == 0) && Player.CanChange()) {
+	if (MouseIn(1815, 75, 90, 90)) {
+		GameMagicBattleExit();
+		return;
+	}
+	if (MouseIn(1815, 190, 90, 90) && (GameMagicBattleGetStatus() == "") && (Player.Game.MagicBattle.House.indexOf("House") == 0) && Player.CanChange()) {
 		MagicSchoolLaboratoryPrepareNPC(Player, Player.Game.MagicBattle.House.replace("House", ""));
 		ChatRoomCharacterUpdate(Player);
+		return;
 	}
 
 	// When the user changes house/role
-	if (MouseIn(900, 218, 600, 64) && (GameMagicBattleStatus == "")) {
+	if (MouseIn(900, 218, 600, 64) && (GameMagicBattleGetStatus() == "")) {
 
 		// Back button
 		if (MouseX < 1200) {
@@ -208,20 +238,26 @@ function GameMagicBattleClick() {
 				else Player.Game.MagicBattle.House = "NotPlaying";
 			} else Player.Game.MagicBattle.House = (Player.Game.MagicBattle.House == "NotPlaying") ? "Independent" : "NotPlaying";
 		}
-
+		return;
 	}
 
 	// When the user selects a new team configuration, we update that player for everyone
-	if (MouseIn(900, 343, 600, 64) && (GameMagicBattleStatus == "") && GameMagicBattleIsAdmin(Player)) {
+	if (MouseIn(900, 343, 600, 64) && (GameMagicBattleGetStatus() == "") && GameMagicBattleIsAdmin(Player)) {
 		Player.Game.MagicBattle.TeamType = (Player.Game.MagicBattle.TeamType == "House") ? "FreeForAll" : "House";
 		ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
+		return;
 	}
 
 	// If the administrator wants to start the game or end the game
-	if (MouseIn(1000, 600, 400, 65) && GameMagicBattleCanLaunchGame()) GameMagicBattleStartProcess();
-	if (MouseIn(1000, 600, 400, 65) && GameMagicBattleIsAdmin(Player) && (GameMagicBattleStatus != "")) {
+	if (MouseIn(1000, 600, 400, 65) && GameMagicBattleCanLaunchGame()) {
+		CommonSetScreen("Online", "ChatRoom");
+		GameMagicBattleStartProcess();
+		return;
+	}
+	if (MouseIn(1000, 600, 400, 65) && GameMagicBattleIsAdmin(Player) && (GameMagicBattleGetStatus() != "")) {
 		CommonSetScreen("Online", "ChatRoom");
 		ServerSend("ChatRoomGame", { GameProgress: "Stop" });
+		return;
 	}
 
 }
@@ -233,7 +269,7 @@ function GameMagicBattleClick() {
 function GameMagicBattleExit() {
 
 	// When the game isn't running, we allow to change the class or team
-	if (GameMagicBattleStatus == "") {
+	if (GameMagicBattleGetStatus() == "") {
 		ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
 		ChatRoomCharacterUpdate(Player);
 	}
@@ -246,7 +282,7 @@ function GameMagicBattleExit() {
  * @returns {boolean} - Returns TRUE if the game can be launched
  */
 function GameMagicBattleCanLaunchGame() {
-	if (GameMagicBattleStatus != "") return false;
+	if (GameMagicBattleGetStatus() != "") return false;
 	if (!GameMagicBattleIsAdmin(Player)) return false;
 	if ((Player.Game.MagicBattle.TeamType != "House") && (Player.Game.MagicBattle.TeamType != "FreeForAll")) return false;
 	var House = "";
@@ -298,7 +334,7 @@ function GameMagicBattleCharacterClick(C) {
 	if (GameMagicBattleTurnDone || !Player.CanTalk()) return true;
 
 	// We allow clicking on a participating room member that's not gagged
-	if ((GameMagicBattleStatus == "Running") && (C.Game != null) && (C.Game.MagicBattle != null) && (C.Game.MagicBattle.House != null) && (C.Game.MagicBattle.House != "NotPlaying") && C.CanTalk())
+	if ((GameMagicBattleGetStatus() == "Running") && (C.Game != null) && (C.Game.MagicBattle != null) && (C.Game.MagicBattle.House != null) && (C.Game.MagicBattle.House != "NotPlaying") && C.CanTalk())
 		GameMagicBattleFocusCharacter = (C.MemberNumber == Player.MemberNumber) ? null : C;
 
 	// Cannot target a player from it's own house if playing in teams by houses
@@ -362,7 +398,7 @@ function GameMagicBattleBuildPlayerList() {
 
 /**
  * Calculates the turn winner and applies the consequences.
- * @returns {void} - Nothing
+ * @returns {OnlineGameStatus}
  */
 function GameMagicBattleCalculateTurnWinner() {
 
@@ -412,13 +448,13 @@ function GameMagicBattleCalculateTurnWinner() {
 	// If there's a winner, we announce it, if the player was representing a house, she can rain reputation
 	if (HouseCount <= 1) {
 		GameMagicBattleAddChatLog("GameOver", Player, Player, null, "#0000A0");
-		GameMagicBattleStatus = "";
+		GameMagicBattleSetStatus("");
 		if (Player.CanTalk() && (Player.Game != null) && (Player.Game.MagicBattle != null) && (Player.Game.MagicBattle.House != null) && (Player.Game.MagicBattle.House.indexOf("House") == 0))
 			DialogChangeReputation(Player.Game.MagicBattle.House, 3);
 	}
 
 	// Returns the game status for the next round
-	return GameMagicBattleStatus;
+	return GameMagicBattleGetStatus();
 }
 
 /**
@@ -431,7 +467,7 @@ function GameMagicBattleProcess(P) {
 
 		// An administrator can start the Magic Battle game, he becomes the turn admin in the process
 		if ((ChatRoomData.Admin.indexOf(P.Sender) >= 0) && (P.Data.GameProgress == "Start")) {
-			GameMagicBattleStatus = "Running";
+			GameMagicBattleSetStatus("Running");
 			GameMagicBattleTurnAdmin = P.Sender;
 			GameMagicBattleBuildPlayerList();
 			GameMagicBattleNewTurn("GameStart" + GameMagicBattleGetTeamType());
@@ -442,19 +478,17 @@ function GameMagicBattleProcess(P) {
 			let Source = GameMagicBattleGetPlayer(P.Sender);
 			if (Source != null) {
 				GameMagicBattleAddChatLog("GameStop", Source, Source, null, "#0000A0");
-				GameMagicBattleStatus = "";
-				Player.Game.MagicBattle.Status = "";
-				ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
+				GameMagicBattleSetStatus("");
 			}
 		}
 
 		// When the turn administrator sends the message to end the turn, we calculate the outcome
-		if ((GameMagicBattleStatus == "Running") && (GameMagicBattleTurnAdmin == P.Sender) && (P.Data.GameProgress == "Next"))
+		if ((GameMagicBattleGetStatus() == "Running") && (GameMagicBattleTurnAdmin == P.Sender) && (P.Data.GameProgress == "Next"))
 			if (GameMagicBattleCalculateTurnWinner() == "Running")
 				GameMagicBattleNewTurn("TurnNext");
 
 		// The current turn player can trigger an action, a spell cast by a user
-		if ((GameMagicBattleStatus == "Running") && (P.Data.GameProgress == "Action") && (P.Data.Action != null) && (P.Data.Target != null)) {
+		if ((GameMagicBattleGetStatus() == "Running") && (P.Data.GameProgress == "Action") && (P.Data.Action != null) && (P.Data.Target != null)) {
 
 			// Keep the data in the game log for that turn
 			GameMagicBattleLog.push({ Sender: P.Sender, Data: P.Data });
@@ -475,9 +509,52 @@ function GameMagicBattleProcess(P) {
  * @returns {void} - Nothing
  */
 function GameMagicBattleReset() {
-	GameMagicBattleStatus = "";
-	if ((Player.Game != null) && (Player.Game.MagicBattle != null) && (Player.Game.MagicBattle.Status != null) && (Player.Game.MagicBattle.Status != "")) {
-		Player.Game.MagicBattle.Status = "";
-		ServerAccountUpdate.QueueData({ Game: Player.Game }, true);
+	GameMagicBattleSetStatus("");
+}
+
+/**
+ * Ensure all character's MagicBattle game status are the same
+ */
+function GameMagicBattleLoadStatus() {
+	for (let C = 0; C < ChatRoomCharacter.length; C++)
+		if ((ChatRoomData.Admin.indexOf(ChatRoomCharacter[C].MemberNumber) >= 0) && (ChatRoomCharacter[C].Game != null) && (ChatRoomCharacter[C].Game.MagicBattle != null) && (ChatRoomCharacter[C].Game.MagicBattle.Status != "")) {
+			GameMagicBattleSetStatus(ChatRoomCharacter[C].Game.MagicBattle.Status);
+			return;
+		}
+	GameMagicBattleReset();
+}
+
+
+/**
+ * Draws the online game images/text needed on the characters
+ * @param {Character} C - Character to draw the info for
+ * @param {number} X - Position of the character the X axis
+ * @param {number} Y - Position of the character the Y axis
+ * @param {number} Zoom - Amount of zoom the character has (Height)
+ * @returns {void} - Nothing
+ */
+function GameMagicBattleDrawCharacter(C, X, Y, Zoom) {
+	// Magic battle draws the timer and the spell buttons
+	if ((CurrentModule == "Online") && (CurrentScreen == "ChatRoom")) {
+		GameMagicBattleDrawIcon(C, X + 70 * Zoom, Y + 800 * Zoom, 0.6 * Zoom);
+		if (Player.CanTalk() && (GameMagicBattleGetStatus() == "Running")) {
+			if (C.MemberNumber == Player.MemberNumber) {
+				MainCanvas.font = CommonGetFont(72);
+				let Time = Math.ceil((GameMagicBattleTurnTimer - TimerGetTime()) / 1000);
+				let Color = "#00FF00";
+				if (Time <= 15) Color = "#FFFF00";
+				if (Time <= 6) Color = "#FF0000";
+				DrawText(((Time < 0) || (Time > GameMagicBattleTimerDelay)) ? OnlineGameDictionaryText("TimerNA") : Time.toString(), X + 250 * Zoom, Y + 830 * Zoom, Color, "Black");
+				MainCanvas.font = CommonGetFont(36);
+			}
+			if ((GameMagicBattleFocusCharacter != null) && (C.MemberNumber == GameMagicBattleFocusCharacter.MemberNumber) && (GameMagicBattleGetStatus() == "Running")) {
+				GameMagicBattleButton = [];
+				for (let S = 0; S < MagicBattleAvailSpell.length; S++) {
+					let B = { X: X + 50 * Zoom, Y: Y + (400 + (S * 100)) * Zoom, W: 400 * Zoom, H: 60 * Zoom };
+					GameMagicBattleButton.push(B);
+					DrawButton(B.X, B.Y, B.W, B.H, OnlineGameDictionaryText("Spell" + MagicBattleAvailSpell[S].toString() + "Name"), "White");
+				}
+			}
+		}
 	}
 }
diff --git a/BondageClub/Screens/Room/AsylumGGTS/AsylumGGTS.js b/BondageClub/Screens/Room/AsylumGGTS/AsylumGGTS.js
index 5b012dd55c..33a5d7725a 100644
--- a/BondageClub/Screens/Room/AsylumGGTS/AsylumGGTS.js
+++ b/BondageClub/Screens/Room/AsylumGGTS/AsylumGGTS.js
@@ -1195,3 +1195,43 @@ function AsylumGGTSAllowChange(C) {
 	}
 	return true;
 }
+
+/**
+ * Draws the online game images/text needed on the characters
+ * @param {Character} C - Character to draw the info for
+ * @param {number} X - Position of the character the X axis
+ * @param {number} Y - Position of the character the Y axis
+ * @param {number} Zoom - Amount of zoom the character has (Height)
+ * @returns {void} - Nothing
+ */
+function AsylumGGTSDrawCharacter(C, X, Y, Zoom) {
+	// GGTS Draws the level, the number of strikes and a progress bar, level 6 shows the time in a gold frame
+	if ((CurrentModule == "Online") && (CurrentScreen == "ChatRoom") && (ChatRoomSpace === "Asylum")) {
+		let Level = AsylumGGTSGetLevel(C);
+		if ((Level > 0) && (C.Game != null) && (C.Game.GGTS != null)) {
+			if (C.Game.GGTS.Strike >= 1) DrawImageZoomCanvas("Screens/Room/AsylumGGTS/Strike" + C.Game.GGTS.Strike.toString() + ".png", MainCanvas, 0, 0, 100, 50, X + 50 * Zoom, Y + 800 * Zoom, 100 * Zoom, 50 * Zoom);
+			MainCanvas.font = CommonGetFont(Math.round(36 * Zoom));
+			let Progress = Math.floor(C.Game.GGTS.Time / AsylumGGTSLevelTime[Level] * 100);
+			if (C.Game.GGTS.Strike >= 3) Progress = 0;
+			if ((Level >= 6) || (Progress >= 100)) DrawEmptyRect(X + 50 * Zoom, Y + 860 * Zoom, 100 * Zoom, 40 * Zoom, "Black");
+			if (Level >= 6) DrawRect(X + 52 * Zoom, Y + 862 * Zoom, 96 * Zoom, 36 * Zoom, "#FFD700");
+			else if (Progress >= 100) DrawRect(X + 50 * Zoom, Y + 860 * Zoom, 100 * Zoom, 40 * Zoom, "White");
+			else DrawProgressBar(X + 50 * Zoom, Y + 860 * Zoom, 100 * Zoom, 40 * Zoom, Progress);
+			if (Level >= 6) DrawText(Math.floor(C.Game.GGTS.Time / 60000).toString(), X + 100 * Zoom, Y + 881 * Zoom, "Black", "White");
+			else if (Progress >= 50) DrawText(Level.toString(), X + 100 * Zoom, Y + 881 * Zoom, "Black", "White");
+			else DrawText(Level.toString(), X + 101 * Zoom, Y + 882 * Zoom, "White", "Black");
+			if (C.Game.GGTS.Rule != null)
+				for (let R = 0; R < C.Game.GGTS.Rule.length; R++)
+					DrawImageZoomCanvas("Screens/Room/AsylumGGTS/Rule" + C.Game.GGTS.Rule[R] + ".png", MainCanvas, 0, 0, 33, 33, X + 50 * Zoom + R * 33 * Zoom, Y + 902 * Zoom, 33 * Zoom, 33 * Zoom);
+			if ((C.ID == 0) && (AsylumGGTSTimer > 0) && (AsylumGGTSTimer > CommonTime()) && (C.Game.GGTS.Strike < 3)) {
+				let ForeColor = (AsylumGGTSTask == null) ? "Black" : "White";
+				let BackColor = (ForeColor == "White") ? "Black" : "White";
+				if ((BackColor == "Black") && (Math.round((AsylumGGTSTimer - CommonTime()) / 1000) <= 10)) BackColor = "Red";
+				DrawEmptyRect(X + 350 * Zoom, Y + 860 * Zoom, 100 * Zoom, 40 * Zoom, ForeColor, 2);
+				DrawRect(X + 352 * Zoom, Y + 862 * Zoom, 96 * Zoom, 36 * Zoom, BackColor);
+				DrawText(Math.round((AsylumGGTSTimer - CommonTime()) / 1000).toString(), X + 399 * Zoom, Y + 882 * Zoom, ForeColor, "Silver");
+			}
+			MainCanvas.font = CommonGetFont(36);
+		}
+	}
+}
diff --git a/BondageClub/Scripts/Typedef.d.ts b/BondageClub/Scripts/Typedef.d.ts
index 6b66edb56b..bf5e1cdd21 100644
--- a/BondageClub/Scripts/Typedef.d.ts
+++ b/BondageClub/Scripts/Typedef.d.ts
@@ -696,7 +696,11 @@ interface Character {
 		GameVersion: string;
 		ItemsAffectExpressions: boolean;
 	};
-	Game?: any;
+	Game?: {
+		LARP?: GameLARPParameters,
+		MagicBattle?: GameMagicBattleParameters,
+		GGTS?: GameGGTSParameters,
+	};
 	BlackList: number[];
 	RunScripts?: boolean;
 	HasScriptedAssets?: boolean;
@@ -1497,3 +1501,42 @@ interface PokerPlayer {
 	WebLink?: string;
 	Alternate?: void;
 }
+
+// #region Online Games
+
+/**
+ * Online game status values.
+ *
+ * @property "" - The game is in the setup phase.
+ * @property "Running" - The game is currently running.
+ *
+ * @fix FIXME: "" should really be renamed Setup
+ */
+type OnlineGameStatus = "" | "Running";
+
+interface GameLARPParameters {
+	Status: OnlineGameStatus;
+	Class: string;
+	Team: string;
+	TimerDelay: number;
+	Level: {
+		Name: string;
+		Level: number;
+		Progress: number;
+	}[];
+}
+
+interface GameMagicBattleParameters {
+	Status: OnlineGameStatus;
+	House: string;
+	TeamType: "FreeForAll" | "House";
+}
+
+interface GameGGTSParameters {
+	Level: number;
+	Time: number;
+	Strike: number;
+	Rule: string[];
+}
+
+// #endregion