diff --git a/js/save.js b/js/save.js
index 97c7b1ac6458e3555e790abea539b44bec901cfc..3820a83c292432355b610ba30c06d2d9a755c5d0 100644
--- a/js/save.js
+++ b/js/save.js
@@ -95,7 +95,7 @@ function Save() {
         'female': [ 'jacket', 'tank top', 'bra', 'belt', 'pants', 'panties', 'stockings', 'shoes' ],
     };
     this.loadPlayer = function() {
-        var gender = players[HUMAN_PLAYER].gender;
+        var gender = humanPlayer.gender;
         var profile = {};
         try {
             profile = JSON.parse(localStorage.getItem(prefix + gender)) || { };
@@ -110,20 +110,20 @@ function Save() {
         playerTagSelections = profile.tags || {};
     };
     this.savePlayer = function(){
-        localStorage.setItem(prefix + 'gender', players[HUMAN_PLAYER].gender);
+        localStorage.setItem(prefix + 'gender', humanPlayer.gender);
     /*  var tags = {};
         for (var key in playerTagSelections) {
             tags[key] = playerTagSelections[key];
         }*/
         var profile = {
             name: $nameField.val(),
-            size: players[HUMAN_PLAYER].size,
+            size: humanPlayer.size,
             tags: playerTagSelections,
-            clothing: clothingChoices[players[HUMAN_PLAYER].gender].filter(function(item, ix) {
+            clothing: clothingChoices[humanPlayer.gender].filter(function(item, ix) {
                 return selectedChoices[ix];
             }).map(function(item) { return item.name; }),
         };
-        localStorage.setItem(prefix + players[HUMAN_PLAYER].gender, JSON.stringify(profile));
+        localStorage.setItem(prefix + humanPlayer.gender, JSON.stringify(profile));
     };
     this.loadOptions = function(){
         try {
@@ -147,7 +147,7 @@ function Save() {
         }
         try {
             var settings = JSON.parse(localStorage.getItem(prefix + 'settings')) || {};
-            if ('stamina' in settings) players[HUMAN_PLAYER].stamina = settings.stamina;
+            if ('stamina' in settings) humanPlayer.stamina = settings.stamina;
             if ('background' in settings) setBackground(settings.background);
         } catch (ex) {
             console.error('Failed parsing settings from localStorage');
@@ -158,7 +158,7 @@ function Save() {
         }
         var gender = localStorage.getItem(prefix + 'gender');
         if (gender) {
-            players[HUMAN_PLAYER].gender = gender;
+            humanPlayer.gender = gender;
         }
     };
     this.saveUsageTracking = function() {
@@ -179,7 +179,7 @@ function Save() {
         localStorage.setItem(prefix + 'options', JSON.stringify(options));
     };
     this.saveSettings = function() {
-        var settings = { stamina: players[HUMAN_PLAYER].stamina };
+        var settings = { stamina: humanPlayer.stamina };
         if (selectedBackground != defaultBackground) {
             settings.background = selectedBackground;
         }
diff --git a/js/spniBehaviour.js b/js/spniBehaviour.js
index 62eb8f141ae98a0deaed69af8a5a3c40a3bef1c1..bc3dc341201d744ef42163c07a75c23847e58d88 100644
--- a/js/spniBehaviour.js
+++ b/js/spniBehaviour.js
@@ -525,7 +525,7 @@ function expandDialogue (dialogue, self, target, bindings) {
         try {
             switch (variable.toLowerCase()) {
             case 'player':
-                substitution = expandNicknames(self, players[HUMAN_PLAYER]);
+                substitution = expandNicknames(self, humanPlayer);
                 break;
             case 'name':
                 substitution = expandNicknames(self, target);
@@ -1664,7 +1664,7 @@ function updateAllVolatileBehaviours () {
         var anyUpdated = false;
         
         players.forEach(function (p) {
-            if (p !== players[HUMAN_PLAYER]) {
+            if (p !== humanPlayer) {
                 anyUpdated = p.updateVolatileBehaviour() || anyUpdated;
             }
         });
@@ -1682,14 +1682,14 @@ function updateAllVolatileBehaviours () {
 function commitAllBehaviourUpdates () {
     /* Apply setLabel first so that ~name~ is the same for all players */
     players.forEach(function (p) {
-        if (p !== players[HUMAN_PLAYER] && p.chosenState && p.chosenState.setLabel) {
+        if (p !== humanPlayer && p.chosenState && p.chosenState.setLabel) {
             p.label = p.chosenState.setLabel;
             p.labelOverridden = true;
         }
     });
     
     players.forEach(function (p) {
-        if (p !== players[HUMAN_PLAYER]) {
+        if (p !== humanPlayer) {
             p.commitBehaviourUpdate();
         }
     });
diff --git a/js/spniClothing.js b/js/spniClothing.js
index c64157d0fdf597b4ae6338b5c45cecc40ed8d9c9..5f22db1371d4c4ddd2aaaf4ee93f9376f4088c94 100644
--- a/js/spniClothing.js
+++ b/js/spniClothing.js
@@ -224,7 +224,7 @@ function playerMustStrip (player) {
 		if (player == HUMAN_PLAYER) {
 			var trigger;
 			if (clothing.length == 1 && clothing[0].type == IMPORTANT_ARTICLE) {
-				if (players[HUMAN_PLAYER].gender == eGender.MALE) {
+				if (humanPlayer.gender == eGender.MALE) {
 					if (clothing[0].position == LOWER_ARTICLE) {
 						trigger = [[MALE_CROTCH_WILL_BE_VISIBLE, OPPONENT_CROTCH_WILL_BE_VISIBLE]];
 					} else {
@@ -237,9 +237,9 @@ function playerMustStrip (player) {
 						trigger = [[FEMALE_CHEST_WILL_BE_VISIBLE, OPPONENT_CHEST_WILL_BE_VISIBLE]];
 					}
 				}
-				players[HUMAN_PLAYER].removedClothing = clothing[0];
+				humanPlayer.removedClothing = clothing[0];
 			} else {
-				if (players[HUMAN_PLAYER].gender == eGender.MALE) {
+				if (humanPlayer.gender == eGender.MALE) {
 				    trigger = [[MALE_HUMAN_MUST_STRIP, OPPONENT_LOST], [MALE_MUST_STRIP, OPPONENT_LOST]];
 				} else {
 				    trigger = [[FEMALE_HUMAN_MUST_STRIP, OPPONENT_LOST], [FEMALE_MUST_STRIP, OPPONENT_LOST]];
@@ -285,7 +285,7 @@ function prepareToStripPlayer (player) {
 		updateAllBehaviours(
 			player,
 			null,
-			players[HUMAN_PLAYER].gender == eGender.MALE ? MALE_HUMAN_MUST_STRIP : FEMALE_HUMAN_MUST_STRIP
+			humanPlayer.gender == eGender.MALE ? MALE_HUMAN_MUST_STRIP : FEMALE_HUMAN_MUST_STRIP
 		);
     } else {
         var toBeRemovedClothing = players[player].clothing[players[player].clothing.length - 1];
@@ -315,10 +315,10 @@ function showStrippingModal () {
   $stripClothing.html("");
 
   /* load the player's clothing into the modal */
-  for (var i = 0; i < players[HUMAN_PLAYER].clothing.length; i++) {
+  for (var i = 0; i < humanPlayer.clothing.length; i++) {
     var clothingCard =
       "<div class='clothing-modal-container'><input type='image' class='bordered modal-clothing-image' src="+
-      players[HUMAN_PLAYER].clothing[i].image+" onclick='selectClothingToStrip.bind(this)("+i+")'/></div>";
+      humanPlayer.clothing[i].image+" onclick='selectClothingToStrip.bind(this)("+i+")'/></div>";
 
     $stripClothing.append(clothingCard);
   }
@@ -340,8 +340,8 @@ function showStrippingModal () {
  ************************************************************/
 function selectClothingToStrip (id) {
   console.log(id);
-  if (players[HUMAN_PLAYER].clothing.length <= id) {
-    console.error('Error: Attempted to select clothing out of bounds', id, players[HUMAN_PLAYER].clothing);
+  if (humanPlayer.clothing.length <= id) {
+    console.error('Error: Attempted to select clothing out of bounds', id, humanPlayer.clothing);
     return;
   }
 
@@ -361,7 +361,7 @@ function clothing_keyUp(e) {
         && $('.modal-clothing-image:focus').not('.modal-selected-clothing-image').length == 0) {
 		$stripButton.click();
         e.preventDefault();
-    } else if (e.keyCode >= 49 && e.keyCode < 49 + players[HUMAN_PLAYER].clothing.length) { // A number key
+    } else if (e.keyCode >= 49 && e.keyCode < 49 + humanPlayer.clothing.length) { // A number key
         $('.clothing-modal-container:nth-child('+(e.keyCode - 48)+') > .modal-clothing-image').focus().click();
     }
 }
@@ -377,21 +377,21 @@ function closeStrippingModal (id) {
 		$stripClothing.html("");
 				
         /* grab the removed article of clothing */
-        var removedClothing = players[HUMAN_PLAYER].clothing[id];
+        var removedClothing = humanPlayer.clothing[id];
 
-        players[HUMAN_PLAYER].clothing.splice(id, 1);
-        players[HUMAN_PLAYER].timeInStage = -1;
-        players[HUMAN_PLAYER].removedClothing = removedClothing;
+        humanPlayer.clothing.splice(id, 1);
+        humanPlayer.timeInStage = -1;
+        humanPlayer.removedClothing = removedClothing;
 
         /* figure out if it should be important */
         if ([UPPER_ARTICLE, LOWER_ARTICLE, FULL_ARTICLE].indexOf(removedClothing.position) >= 0
             && (removedClothing.type == IMPORTANT_ARTICLE || removedClothing.type == MAJOR_ARTICLE)) {
             var otherClothing;
-            for (var i = 0; i < players[HUMAN_PLAYER].clothing.length; i++) {
-                if (players[HUMAN_PLAYER].clothing[i].position === removedClothing.position
-                    && players[HUMAN_PLAYER].clothing[i].type != MINOR_ARTICLE) {
-                    console.log(players[HUMAN_PLAYER].clothing[i]);
-                    otherClothing = players[HUMAN_PLAYER].clothing[i];
+            for (var i = 0; i < humanPlayer.clothing.length; i++) {
+                if (humanPlayer.clothing[i].position === removedClothing.position
+                    && humanPlayer.clothing[i].type != MINOR_ARTICLE) {
+                    console.log(humanPlayer.clothing[i]);
+                    otherClothing = humanPlayer.clothing[i];
                     break;
                 }
             }
@@ -407,27 +407,27 @@ function closeStrippingModal (id) {
             }
         }
         if ([IMPORTANT_ARTICLE, MAJOR_ARTICLE, MINOR_ARTICLE].indexOf(removedClothing.type) >= 0) {
-            players[HUMAN_PLAYER].mostlyClothed = false;
+            humanPlayer.mostlyClothed = false;
         }
         if ([IMPORTANT_ARTICLE, MAJOR_ARTICLE].indexOf(removedClothing.type) >= 0
 			&& [UPPER_ARTICLE, LOWER_ARTICLE, FULL_ARTICLE].indexOf(removedClothing.position) >= 0) {
-            players[HUMAN_PLAYER].decent = false;
+            humanPlayer.decent = false;
         }
         if (removedClothing.type == IMPORTANT_ARTICLE) {
-            players[HUMAN_PLAYER].exposed[removedClothing.position] = true;
+            humanPlayer.exposed[removedClothing.position] = true;
         }
         
         /* determine its dialogue trigger */
-        var dialogueTrigger = getClothingTrigger(players[HUMAN_PLAYER], removedClothing, true);
+        var dialogueTrigger = getClothingTrigger(humanPlayer, removedClothing, true);
         console.log(removedClothing);
         /* display the remaining clothing */
         displayHumanPlayerClothing();
         
         /* count the clothing the player has remaining */
-        players[HUMAN_PLAYER].stage++
+        humanPlayer.stage++
         
         /* update label */
-        if (players[HUMAN_PLAYER].clothing.length > 0) {
+        if (humanPlayer.clothing.length > 0) {
             $gameClothingLabel.html("Your Remaining Clothing");
         } else {
             $gameClothingLabel.html("You're Naked");
diff --git a/js/spniCore.js b/js/spniCore.js
index d4ba978a17683ea90945511af8c2ad5656b26200..b8c574b1254f5d7b222ea2e6ebc1c19c970ba440 100644
--- a/js/spniCore.js
+++ b/js/spniCore.js
@@ -56,6 +56,7 @@ var BLANK_PLAYER_IMAGE = "opponents/blank.png";
 
 /* player array */
 var players = Array(5);
+var humanPlayer;
 
 /* Current timeout ID, so we can cancel it when restarting the game in order to avoid trouble. */
 var timeoutID;
@@ -186,8 +187,8 @@ function compileBaseErrorReport(userDesc, bugType) {
         'circumstances': circumstances,
         'table': tableReports,
         'player': {
-            'gender': players[HUMAN_PLAYER].gender,
-            'size': players[HUMAN_PLAYER].size,
+            'gender': humanPlayer.gender,
+            'size': humanPlayer.size,
         },
         'jsErrors': jsErrors,
     };
@@ -979,9 +980,9 @@ Player.prototype.preloadStageImages = function (stage) {
  ************************************************************/
 function initialSetup () {
     /* start by creating the human player object */
-    var humanPlayer = new Player('human'); //createNewPlayer("human", "", "", "", eGender.MALE, eSize.MEDIUM, eIntelligence.AVERAGE, 20, undefined, [], null);
-    players[HUMAN_PLAYER] = humanPlayer;
-    players[HUMAN_PLAYER].slot = HUMAN_PLAYER;
+    humanPlayer = new Player('human'); //createNewPlayer("human", "", "", "", eGender.MALE, eSize.MEDIUM, eIntelligence.AVERAGE, 20, undefined, [], null);
+    humanPlayer = humanPlayer;
+    humanPlayer.slot = HUMAN_PLAYER;
 
 	/* enable table opacity */
 	tableOpacity = 1;
@@ -1715,7 +1716,7 @@ function showPlayerTagsModal () {
     $('#player-tags-confirm').one('click', function() {
         playerTagSelections = {};
         for (var choiceName in playerTagOptions) {
-            if (!('gender' in playerTagOptions[choiceName]) || playerTagOptions[choiceName].gender == players[HUMAN_PLAYER].gender) {
+            if (!('gender' in playerTagOptions[choiceName]) || playerTagOptions[choiceName].gender == humanPlayer.gender) {
                 var val = $('form#player-tags [name="'+choiceName+'"]').val();
                 if (val) {
                     playerTagSelections[choiceName] = val;
@@ -1803,16 +1804,18 @@ if (!String.prototype.startsWith) {
  * Counts the number of elements that evaluate as true, or,
  * if a function is provided, passes the test implemented by it.
  ************************************************************/
-Array.prototype.countTrue = function(func) {
-    var count = 0;
-    for (var i = 0; i < this.length; i++) {
-        if (i in this
-            && (func ? func(this[i], i, this) : this[i])) {
-            count++;
+Object.defineProperty(Array.prototype, 'countTrue', {
+    value: function(func) {
+        var count = 0;
+        for (var i = 0; i < this.length; i++) {
+            if (i in this
+                && (func ? func(this[i], i, this) : this[i])) {
+                count++;
+            }
         }
+        return count;
     }
-    return count;
-}
+});
 
 /************************************************************
  * Generate a random alphanumeric ID.
@@ -1861,11 +1864,6 @@ function autoResizeFont ()
 	window.onresize = autoResizeFont;
 }
 
-/* Get the number of players loaded, including the human player.*/
-function countLoadedOpponents() {
-    return players.reduce(function (a, v) { return a + (v ? 1 : 0); }, 0);
-}
-
 $('.modal').on('show.bs.modal', function() {
 	$('.screen:visible').find('button, input').attr('tabIndex', -1);
 });
diff --git a/js/spniDevMode.js b/js/spniDevMode.js
index 85c6e7cf41141c16820e23fe95daab5910fd1d5d..51650947a64aeaa851d4a68213b3eb6dff7e34b4 100644
--- a/js/spniDevMode.js
+++ b/js/spniDevMode.js
@@ -44,7 +44,7 @@ function setDevModeTarget (target) {
         $('#dev-select-button-'+target).addClass('active');
         
         players.forEach(function (p) {
-            if (p !== players[HUMAN_PLAYER] && !p.devModeInitialized) p.initDevMode();
+            if (p !== humanPlayer && !p.devModeInitialized) p.initDevMode();
         })
     }
     
diff --git a/js/spniDisplay.js b/js/spniDisplay.js
index 72ca30cede6579e1c2b4c97fd5857d8e68ea31a6..4723817307ef106ed66ba012d22457e347ed8326 100644
--- a/js/spniDisplay.js
+++ b/js/spniDisplay.js
@@ -1211,9 +1211,9 @@ OpponentDetailsDisplay.prototype.update = function (opponent) {
         if (endingGenders.male && endingGenders.female) {
             epilogueAvailable = true;
         } else if (endingGenders.male) {
-            epilogueAvailable = (players[HUMAN_PLAYER].gender === 'male');
+            epilogueAvailable = (humanPlayer.gender === 'male');
         } else if (endingGenders.female) {
-            epilogueAvailable = (players[HUMAN_PLAYER].gender === 'female');
+            epilogueAvailable = (humanPlayer.gender === 'female');
         }
         
         if (epilogueAvailable) {
diff --git a/js/spniEpilogue.js b/js/spniEpilogue.js
index 2a3efad8a0dffc297eee543ff2ee18d8c6fc0742..ca2c62aa1683f5da7574a539a2bebb2448a83d15 100644
--- a/js/spniEpilogue.js
+++ b/js/spniEpilogue.js
@@ -273,7 +273,7 @@ function loadEpilogueData(player) {
     return [];
   }
 
-  var playerGender = players[HUMAN_PLAYER].gender;
+  var playerGender = humanPlayer.gender;
 
   //get the XML tree that relates to the epilogue, for the specific player gender
   //var epXML = $($.parseXML(xml)).find('epilogue[gender="'+playerGender+'"]'); //use parseXML() so that <image> tags come through properly //IE doesn't like this
@@ -296,7 +296,7 @@ function loadEpilogueData(player) {
     }
 
     var playerStartingLayers = parseInterval($(this).attr('playerStartingLayers'));
-    if (playerStartingLayers !== undefined && !inInterval(players[HUMAN_PLAYER].startingLayers, playerStartingLayers)) {
+    if (playerStartingLayers !== undefined && !inInterval(humanPlayer.startingLayers, playerStartingLayers)) {
       return false;
     }
 
@@ -850,7 +850,7 @@ function doEpilogueModal() {
   $epilogueAcceptButton.prop("disabled", true); //don't let the player accept an epilogue until they've chosen one
 
   //whether or not the human player won
-  var playerWon = !players[HUMAN_PLAYER].out;
+  var playerWon = !humanPlayer.out;
 
   if (EPILOGUES_ENABLED && playerWon) { //all the epilogues are for when the player wins, so don't allow them to choose one if they lost
     //load the epilogue data for each player
@@ -1717,7 +1717,7 @@ SceneView.prototype.removeText = function (directive, context) {
 }
 
 SceneView.prototype.applyTextDirective = function (directive, box) {
-  var content = expandDialogue(directive.text, null, players[HUMAN_PLAYER]);
+  var content = expandDialogue(directive.text, null, humanPlayer);
 
   box.html('<span>' + content + '</span>');
   box.addClass(directive.arrow)
diff --git a/js/spniForfeit.js b/js/spniForfeit.js
index 67ce5633807ce758b0ee3e5e8cc67af0d90ceeec..c93be04aa1ac27a2ed8ba5c7e6e697948f155475 100644
--- a/js/spniForfeit.js
+++ b/js/spniForfeit.js
@@ -66,7 +66,7 @@ function startMasturbation (player) {
     
     if (player == HUMAN_PLAYER) {
         $gameClothingLabel.html("You're Masturbating...");
-        $gamePlayerCountdown.html(players[HUMAN_PLAYER].timer);
+        $gamePlayerCountdown.html(humanPlayer.timer);
         $gamePlayerCountdown.show();
     }
     
@@ -171,7 +171,7 @@ function tickForfeitTimers () {
     }
     // Show a player masturbating while dealing or after the game, if there is one available
     if (masturbatingPlayers.length > 0
-        && ((gamePhase == eGamePhase.DEAL && players[HUMAN_PLAYER].out) || gamePhase == eGamePhase.EXCHANGE || gamePhase == eGamePhase.END_LOOP)) {
+        && ((gamePhase == eGamePhase.DEAL && humanPlayer.out) || gamePhase == eGamePhase.EXCHANGE || gamePhase == eGamePhase.END_LOOP)) {
         var playerToShow = masturbatingPlayers[getRandomNumber(0, masturbatingPlayers.length)]
         var others_tags = [[players[playerToShow].gender == eGender.MALE ? MALE_MASTURBATING : FEMALE_MASTURBATING, OPPONENT_MASTURBATING]];
         if (players[playerToShow].forfeit[0] == PLAYER_HEAVY_MASTURBATING) {
diff --git a/js/spniGallery.js b/js/spniGallery.js
index 30d371b7286107bc8924422ce5b0e44d2220e908..81fca7524d82955f11337fa2f3fb06c2542673a7 100644
--- a/js/spniGallery.js
+++ b/js/spniGallery.js
@@ -513,12 +513,12 @@ function doEpilogueFromGallery(){
 			});
 			
 			if($nameField.val()){
-				players[HUMAN_PLAYER].label = $nameField.val();
+				humanPlayer.label = $nameField.val();
 			} else {
 				switch(chosenEpilogue.gender){
-					case "male": players[HUMAN_PLAYER].label = "Mister"; break;
-					case "female" : players[HUMAN_PLAYER].label = "Missy"; break;
-					default: players[HUMAN_PLAYER].label = (players[HUMAN_PLAYER].gender=="male")?"Mister":"Missy";
+					case "male": humanPlayer.label = "Mister"; break;
+					case "female" : humanPlayer.label = "Missy"; break;
+					default: humanPlayer.label = (humanPlayer.gender=="male")?"Mister":"Missy";
 				}
 			}
 			
diff --git a/js/spniGame.js b/js/spniGame.js
index 18f8d76d9a5069601dbdc730d017b40528caa683..7dac2ac7623eaa4eccf3741b1611211b35339b25 100644
--- a/js/spniGame.js
+++ b/js/spniGame.js
@@ -238,7 +238,7 @@ function updateAllGameVisuals () {
  ************************************************************/
 function displayHumanPlayerClothing () {
     /* collect the images */
-    var clothingImages = players[HUMAN_PLAYER].clothing.map(function(c) {
+    var clothingImages = humanPlayer.clothing.map(function(c) {
 		return c.image;
 	});
     
@@ -360,7 +360,7 @@ function advanceTurn () {
         saveTranscriptEntries(updatedPlayers);
         
         /* human player's turn */
-        if (players[HUMAN_PLAYER].out) {
+        if (humanPlayer.out) {
 			allowProgression(eGamePhase.REVEAL);
 		} else {
             $gameScreen.addClass('prompt-exchange');
@@ -440,7 +440,7 @@ function checkDealLock () {
 		   player to exchange cards, and someone is masturbating, and
 		   the card animation speed is to great, we need a pause so
 		   that the masturbation talk can be read. */
-        if (players[HUMAN_PLAYER].out && getNumPlayersInStage(STATUS_MASTURBATING) > 0 && ANIM_DELAY < 100) {
+        if (humanPlayer.out && getNumPlayersInStage(STATUS_MASTURBATING) > 0 && ANIM_DELAY < 100) {
             allowProgression();
         } else {
             continueDealPhase();
@@ -466,12 +466,12 @@ function continueDealPhase () {
     }
 
 	/* suggest cards to swap, if enabled */
-	if (CARD_SUGGEST && !players[HUMAN_PLAYER].out) {
-		determineAIAction(players[HUMAN_PLAYER]);
+	if (CARD_SUGGEST && !humanPlayer.out) {
+		determineAIAction(humanPlayer);
 		
 		/* dull the cards they are trading in */
-		for (var i = 0; i < players[HUMAN_PLAYER].hand.tradeIns.length; i++) {
-			if (players[HUMAN_PLAYER].hand.tradeIns[i]) {
+		for (var i = 0; i < humanPlayer.hand.tradeIns.length; i++) {
+			if (humanPlayer.hand.tradeIns[i]) {
 				dullCard(HUMAN_PLAYER, i);
 			}
 		}
@@ -735,9 +735,9 @@ function handleGameOver() {
  * The player selected one of their cards.
  ************************************************************/
 function selectCard (card) {
-	players[HUMAN_PLAYER].hand.tradeIns[card] = !players[HUMAN_PLAYER].hand.tradeIns[card];
+	humanPlayer.hand.tradeIns[card] = !humanPlayer.hand.tradeIns[card];
 	
-	if (players[HUMAN_PLAYER].hand.tradeIns[card]) {
+	if (humanPlayer.hand.tradeIns[card]) {
 		dullCard(HUMAN_PLAYER, card);
 	} else {
 		fillCard(HUMAN_PLAYER, card);
@@ -755,9 +755,9 @@ function allowProgression (nextPhase) {
 		nextPhase = gamePhase;
 	}
 	
-    if (FORFEIT_DELAY && nextPhase != eGamePhase.GAME_OVER && players[HUMAN_PLAYER].out && players[HUMAN_PLAYER].timer > 1) {
+    if (FORFEIT_DELAY && nextPhase != eGamePhase.GAME_OVER && humanPlayer.out && humanPlayer.timer > 1) {
         timeoutID = autoForfeitTimeoutID = setTimeout(advanceGame, FORFEIT_DELAY);
-    } else if (ENDING_DELAY && nextPhase != eGamePhase.GAME_OVER && (players[HUMAN_PLAYER].finished || (!players[HUMAN_PLAYER].out && gameOver))) {
+    } else if (ENDING_DELAY && nextPhase != eGamePhase.GAME_OVER && (humanPlayer.finished || (!humanPlayer.out && gameOver))) {
         /* Human is finished or human is the winner */
         timeoutID = autoForfeitTimeoutID = setTimeout(advanceGame, ENDING_DELAY);
     } else {
@@ -765,7 +765,7 @@ function allowProgression (nextPhase) {
         actualMainButtonState = false;
     }
 
-	if (players[HUMAN_PLAYER].out && !players[HUMAN_PLAYER].finished && players[HUMAN_PLAYER].timer == 1 && gamePhase != eGamePhase.STRIP) {
+	if (humanPlayer.out && !humanPlayer.finished && humanPlayer.timer == 1 && gamePhase != eGamePhase.STRIP) {
 		$mainButton.html("Cum!");
 	} else if (nextPhase[0]) {
 		$mainButton.html(nextPhase[0]);
diff --git a/js/spniOption.js b/js/spniOption.js
index 0724072161e52f96208dd1a807c2375ac2c7a490..48775f3d6644c37f3590bccbf1ae56a6cfe3b4ee 100644
--- a/js/spniOption.js
+++ b/js/spniOption.js
@@ -180,7 +180,7 @@ function setBackground (choice) {
  * Loading the player masturbation timer.
  ************************************************************/
 function loadMasturbationTimer () {
-	$masturbationTimerBox.val(players[HUMAN_PLAYER].stamina);
+	$masturbationTimerBox.val(humanPlayer.stamina);
 	$masturbationWarningLabel.css("visibility", "hidden");
 }
  /************************************************************
@@ -191,7 +191,7 @@ $masturbationTimerBox.on('input', function() {
 	var newTime = Number(newTimerValue);
 	var isValidTimerValue = (newTime != "NaN") && (newTime > 0);
 	if (isValidTimerValue){
-		players[HUMAN_PLAYER].stamina = newTime;
+		humanPlayer.stamina = newTime;
 	}
 	$masturbationWarningLabel.css("visibility", isValidTimerValue ? "hidden" : "visible");
 });
diff --git a/js/spniSelect.js b/js/spniSelect.js
index 0248a96d6cc66fc58dafd215233234bfeed449be..42ad43d83539f856cd8320d4ccf1987bd22cc0c2 100644
--- a/js/spniSelect.js
+++ b/js/spniSelect.js
@@ -647,8 +647,7 @@ function selectOpponentSlot (slot) {
         /* Make sure the user doesn't have target-count sorting set if
          * the amount of loaded opponents drops to 0. */
         if (sortingMode === "Targeted most by selected") {
-            var player_count = countLoadedOpponents();
-            if (player_count <= 1) {
+            if (players.countTrue() <= 1) {
                 setSortingMode("Featured");
             }
         }
@@ -906,7 +905,7 @@ function advanceSelectScreen () {
             'userAgent': navigator.userAgent,
             'origin': getReportedOrigin(),
             'table': {},
-			'tags': players[HUMAN_PLAYER].tags
+			'tags': humanPlayer.tags
         };
 
         for (let i=1;i<5;i++) {
@@ -1008,9 +1007,7 @@ function updateSelectionVisuals () {
     $groupButton.attr('disabled', loaded < filled);
 
     /* Update suggestions images. */
-    var current_player_count = countLoadedOpponents();
-
-    if (current_player_count >= 3) {
+    if (players.countTrue() >= 3) {
         var suggested_opponents = loadedOpponents.filter(function(opp) {
             /* hide selected opponents */
             if (players.some(function(p) { return p && p.id == opp.id; })) {
diff --git a/js/spniTitle.js b/js/spniTitle.js
index 05397efb9687cca7e0f414e68534f17ad3f8327e..a3502bc6c51b900bf888145c4d07083494098a55 100644
--- a/js/spniTitle.js
+++ b/js/spniTitle.js
@@ -325,19 +325,19 @@ function loadClothing () {
  * Updates the clothing on the title screen.
  ************************************************************/
 function updateTitleClothing () {
-	if (players[HUMAN_PLAYER].gender == eGender.MALE) {
+	if (humanPlayer.gender == eGender.MALE) {
 		$('#female-clothing-container').hide();
 		$('#male-clothing-container').show();
-	} else if (players[HUMAN_PLAYER].gender == eGender.FEMALE) {
+	} else if (humanPlayer.gender == eGender.FEMALE) {
 		$('#male-clothing-container').hide();
 		$('#female-clothing-container').show();
 	}
 
 	for (var i = 0; i < selectedChoices.length; i++) {
 		if (selectedChoices[i]) {
-			$('#'+players[HUMAN_PLAYER].gender+'-clothing-option-'+i).css('opacity', '1');
+			$('#'+humanPlayer.gender+'-clothing-option-'+i).css('opacity', '1');
 		} else {
-			$('#'+players[HUMAN_PLAYER].gender+'-clothing-option-'+i).css('opacity', '0.4');
+			$('#'+humanPlayer.gender+'-clothing-option-'+i).css('opacity', '0.4');
 		}
 	}
 	//$warningLabel.html("");
@@ -353,7 +353,7 @@ function updateTitleClothing () {
  ************************************************************/
 function changePlayerGender (gender) {
 	save.savePlayer();
-	players[HUMAN_PLAYER].gender = gender;
+	humanPlayer.gender = gender;
 	save.loadPlayer();
 	updateTitleGender();
 }
@@ -362,8 +362,8 @@ function changePlayerGender (gender) {
  * Updates the gender dependent controls on the title screen.
  ************************************************************/
 function updateTitleGender() {
-    $titleContainer.removeClass('male female').addClass(players[HUMAN_PLAYER].gender);
-    $playerTagsModal.removeClass('male female').addClass(players[HUMAN_PLAYER].gender);
+    $titleContainer.removeClass('male female').addClass(humanPlayer.gender);
+    $playerTagsModal.removeClass('male female').addClass(humanPlayer.gender);
 
 	updateTitleClothing();
 }
@@ -373,7 +373,7 @@ function updateTitleGender() {
  * screen, or this was called by an internal source.
  ************************************************************/
 function changePlayerSize (size) {
-	players[HUMAN_PLAYER].size = size;
+	humanPlayer.size = size;
 
     $sizeBlocks.removeClass(eSize.SMALL + ' ' + eSize.MEDIUM + ' ' + eSize.LARGE).addClass(size).attr('data-size', size);
 }
@@ -396,8 +396,8 @@ function selectClothing (id) {
  * dialog and the size.
  **************************************************************/
 function setPlayerTags () {
-    var playerTagList = ['human', 'human_' + players[HUMAN_PLAYER].gender,
-                         players[HUMAN_PLAYER].size + (players[HUMAN_PLAYER].gender == 'male' ? '_penis' : '_breasts')];
+    var playerTagList = ['human', 'human_' + humanPlayer.gender,
+                         humanPlayer.size + (humanPlayer.gender == 'male' ? '_penis' : '_breasts')];
 
     for (category in playerTagSelections) {
         var sel = playerTagSelections[category];
@@ -419,8 +419,8 @@ function setPlayerTags () {
     }
     /* applies tags to the player*/
     console.log(playerTagList);
-    players[HUMAN_PLAYER].baseTags = playerTagList.map(canonicalizeTag);
-    players[HUMAN_PLAYER].updateTags();
+    humanPlayer.baseTags = playerTagList.map(canonicalizeTag);
+    humanPlayer.updateTags();
 }
 
 /************************************************************
@@ -433,23 +433,23 @@ function validateTitleScreen () {
     
 	if ($nameField.val() != "") {
         playerName = $nameField.val();
-	} else if (players[HUMAN_PLAYER].gender == "male") {
+	} else if (humanPlayer.gender == "male") {
         playerName = "Mister";
-	} else if (players[HUMAN_PLAYER].gender == "female") {
+	} else if (humanPlayer.gender == "female") {
         playerName = 'Missy';
 	}
     
     // Nuke all angle-brackets
     playerName = playerName.replace(/<|>/g, '');
     
-    players[HUMAN_PLAYER].first = playerName;
-    players[HUMAN_PLAYER].label = playerName;
+    humanPlayer.first = playerName;
+    humanPlayer.label = playerName;
     
-	$gameLabels[HUMAN_PLAYER].html(players[HUMAN_PLAYER].label);
+	$gameLabels[HUMAN_PLAYER].html(humanPlayer.label);
 
 	/* count clothing */
 	var clothingCount = [0, 0, 0, 0];
-	var genderClothingChoices = clothingChoices[players[HUMAN_PLAYER].gender];
+	var genderClothingChoices = clothingChoices[humanPlayer.gender];
 	for (i = 0; i < genderClothingChoices.length; i++) {
 		if (selectedChoices[i]) {
 			if (genderClothingChoices[i].position == UPPER_ARTICLE) {
@@ -495,7 +495,7 @@ function validateTitleScreen () {
 function wearClothing () {
 	var position = [[], [], []];
 	var importantWorn = [false, false];
-    var genderClothingChoices = clothingChoices[players[HUMAN_PLAYER].gender];
+    var genderClothingChoices = clothingChoices[humanPlayer.gender];
 
     /* sort the clothing by position */
     for (var i = genderClothingChoices.length - 1; i >= 0; i--) {
@@ -511,27 +511,27 @@ function wearClothing () {
     }
 
 	/* clear player clothing array */
-	players[HUMAN_PLAYER].clothing = [];
+	humanPlayer.clothing = [];
 
 	/* wear the clothing is sorted order */
 	for (var i = 0; i < position[0].length || i < position[1].length; i++) {
 		/* wear a lower article, if any remain */
 		if (i < position[1].length) {
-			players[HUMAN_PLAYER].clothing.push(position[1][i]);
+			humanPlayer.clothing.push(position[1][i]);
 		}
 
 		/* wear an upper article, if any remain */
 		if (i < position[0].length) {
-			players[HUMAN_PLAYER].clothing.push(position[0][i]);
+			humanPlayer.clothing.push(position[0][i]);
 		}
 	}
 
 	/* wear any other clothing */
 	for (var i = 0; i < position[2].length; i++) {
-		players[HUMAN_PLAYER].clothing.push(position[2][i]);
+		humanPlayer.clothing.push(position[2][i]);
 	}
 
-	players[HUMAN_PLAYER].initClothingStatus();
+	humanPlayer.initClothingStatus();
 
 	/* update the visuals */
     displayHumanPlayerClothing();