Website's Game source code

A Darkroom by doublespeakgames

<!DOCTYPE html>
<html itemscope itemtype="https://schema.org/CreativeWork">
<head>
    <meta charset="UTF-8"/>
    <!--  
        A Dark Room (v1.4)
        ==================
        
        A minimalist text adventure by Michael Townsend and all his friends.
        Inspired by Candy Box (http://candies.aniwey.net/)
        Contribute on GitHub! (https://github.com/doublespeakgames/adarkroom/)
    -->
    <title>A Dark Room</title>
    <meta itemprop="description" name="description" property="og:description" content="A minimalist text adventure">
    <meta itemprop="image" property="og:image" content="img/adr.png" />
    <meta itemprop="name" property="og:title" content="A Dark Room" />
    <link rel="shortcut icon" href="favicon.ico" />
    <link rel="image_src" href="img/adr.png" />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.1/jquery.min.js"></script>
    <script src="https://www.dropbox.com/static/api/dropbox-datastores-1.1-latest.js" type="text/javascript"></script>
    <script>
        if(!window.jQuery) {
            document.write('<script src="lib/jquery.min.js"><\/script>')
        }
    </script>
    <script src="lib/jquery.color-2.1.2.min.js"></script>
    <script src="lib/jquery.event.move.js"></script>
    <script src="lib/jquery.event.swipe.js"></script>
    <script src="lib/base64.js"></script>
    <script src="lib/translate.js"></script>
    
    <script src="lang/langs.js"></script>
    
    <script>
        // try to read "lang" param's from url
        var lang = decodeURIComponent((new RegExp('[?|&]lang=' + '([^&;]+?)(&|#|;|$)').exec(location.search)||[,""])[1].replace(/\+/g, '%20'))||null;
        // if no language requested, try to read it from local storage
        if(!lang){
            try {
                lang = localStorage.lang;
            } catch(e) {}
        }
        // if a language different than english requested, load all translations
        if(lang && lang != 'en'){
            document.write('<script src="lang/'+lang+'/strings.js"><\/script>');
            document.write('<link rel="stylesheet" type="text/css" href="lang/'+lang+'/main.css" \/>');
        }
    </script>
    
    <script src="script/Button.js"></script>
    <script src="script/engine.js"></script>
    <script src="script/state_manager.js"></script>
    <script src="script/header.js"></script>
    <script src="script/notifications.js"></script>
    <script src="script/events.js"></script>
    <script src="script/dropbox.js"></script>
    <script src="script/room.js"></script>
    <script src="script/outside.js"></script>
    <script src="script/world.js"></script>
    <script src="script/path.js"></script>
    <script src="script/ship.js"></script>
    <script src="script/space.js"></script>
    <script src="script/prestige.js"></script>
    <script src="script/scoring.js"></script>
    <!-- Event modules -->
    <script src="script/events/global.js"></script>
    <script src="script/events/room.js"></script>
    <script src="script/events/outside.js"></script>
    <script src="script/events/encounters.js"></script>
    <script src="script/events/setpieces.js"></script>
    
    <script type='text/javascript'>
        var oldIE = false;
    </script>
    <!--[if lt IE 9]> 
        <script type="text/javascript">oldIE = true;</script> 
    <![endif]-->
    
    <link rel="stylesheet" type="text/css" href="css/main.css" />
    <link rel="stylesheet" type="text/css" href="css/room.css" />
    <link rel="stylesheet" type="text/css" href="css/outside.css" />
    <link rel="stylesheet" type="text/css" href="css/path.css" />
    <link rel="stylesheet" type="text/css" href="css/world.css" />
    <link rel="stylesheet" type="text/css" href="css/ship.css" />
    <link rel="stylesheet" type="text/css" href="css/space.css" />
    
    <script src="script/localization.js"></script>
    <!-- Google Analytics -->
    <script>
        (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
        (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
        m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
        })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
        ga('create', 'UA-41314886-1', 'doublespeakgames.com');
        ga('send', 'pageview');
    </script>
    
</head>
<body>
    <div id="wrapper">
        <div id="saveNotify"><script>document.write(_("saved."));</script></div>
        <div id="content">
            <div id="outerSlider">
                <div id="main">
                    <div id="header"></div>
                </div>
            </div>
        </div>
    </div>
</body>
</html>
Source Code

Shellshock.io

!DOCTYPE html>
<html lang="en" xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">



<!-- Styles & Fonts -->
<link href="https://fonts.googleapis.com/css?family=Sigmar+One|Nunito:100,200,600,700,900" rel="stylesheet">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous">
<link rel="stylesheet" href="styles/transitions.css?1566102874">
<link rel="stylesheet" href="styles/forms.css?1566102874">
<link rel="stylesheet" href="styles/style.css?1566102874">
<link rel="stylesheet" href="styles/game.css?1566102874">

<style>
.eggIcon {
    display: inline-block;
    color: #444444;
    width: 1em;
    height: 1em;
    fill: currentColor;
}
</style>
                            
<svg style="position: absolute; width: 0; height: 0; overflow: hidden" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <symbol id="icon-egg" viewBox="0 0 14.59 18.12">
            <path class="eggFill" d="M14.49,10.79c0-3.96-3.02-10.66-6.98-10.66s-7.36,6.7-7.36,10.66s3.21,7.17,7.17,7.17S14.49,14.75,14.49,10.79z"></path>
        </symbol>
    </defs>
</svg>

<style>
.eggIconLocked {
    display: inline-block;
    color: #444444;
    width: 1em;
    height: 1em;
    fill: currentColor;
}
</style>
                            
<svg style="position: absolute; width: 0; height: 0; overflow: hidden" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
    <defs>
        <symbol id="icon-egg-locked" viewBox="0 0 14.59 18.12">
<g>
    <path class="st0" d="M7.3,5.4c-0.6,0-1.1,0.5-1.1,1.1v1.3h2.2V6.5C8.4,5.9,7.9,5.4,7.3,5.4z"/>
    <path class="st0" d="M7.5,0.1c-4,0-7.4,6.7-7.4,10.7S3.4,18,7.3,18c3.9,0,7.2-3.2,7.2-7.2S11.5,0.1,7.5,0.1z M11.3,12.5
        c0,0.9-0.7,1.6-1.6,1.6H4.8c-0.9,0-1.6-0.7-1.6-1.6V7.8h1.5V6.5C4.8,5.1,5.9,4,7.3,4c1.4,0,2.5,1.1,2.5,2.5v1.3h1.5V12.5z"/>
</g>
        </symbol>
    </defs>
</svg>
<!-- European Union detection -->
<script>isFromEU = 0 ? true : false</script>

<!-- AdInPlay -->
<meta name="viewport" content="minimal-ui, user-scalable=no, initial-scale=1, maximum-scale=1, width=device-width" />
<script async src="//api.adinplay.com/libs/aiptag/pub/SSK/shellshock.io/tag.min.js"></script>
<script>
    var aiptag = aiptag || {};
    aiptag.cmd = aiptag.cmd || [];
    aiptag.cmd.display = aiptag.cmd.display || [];
    aiptag.cmd.player = aiptag.cmd.player || [];
</script>

<!-- Google AdManager -->
<script>
        var useAdManager = false;
        console.log('Using GoogleAdManager: ' + useAdManager);
        console.log(useAdManager);
</script>


<!-- Firebase -->
<script src="https://www.gstatic.com/firebasejs/6.0.2/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/6.0.2/firebase-auth.js"></script>

<script src="https://cdn.firebase.com/libs/firebaseui/4.0.0/firebaseui.js"></script>
<link type="text/css" rel="stylesheet" href="https://cdn.firebase.com/libs/firebaseui/4.0.0/firebaseui.css" />

<!-- Facebook -->
<!-- Facebook Pixel Code -->
<script>
    !function(f,b,e,v,n,t,s){if(f.fbq)return;n=f.fbq=function(){n.callMethod?
    n.callMethod.apply(n,arguments):n.queue.push(arguments)};if(!f._fbq)f._fbq=n;
    n.push=n;n.loaded=!0;n.version='2.0';n.queue=[];t=b.createElement(e);t.async=!0;
    t.src=v;s=b.getElementsByTagName(e)[0];s.parentNode.insertBefore(t,s)}(window,
    document,'script','https://connect.facebook.net/en_US/fbevents.js');
    fbq('init', '771186996377132');
    fbq('track', 'PageView');
</script>
<noscript>
    <img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=771186996377132&ev=PageView&noscript=1"/>
</noscript>
<!-- DO NOT MODIFY -->
<!-- End Facebook Pixel Code -->

<!-- ParsedURL -->
<script>
    var parsedUrl = (function parseUrl () {
        var url = {};
        var loc = window.location;
        url.root = loc.origin + loc.pathname;
        var query = loc.search.substring(1).split('&');
        url.query = {};
        for (var i in query) {
            var arr = query[i].split('=');
            if (arr[0]) {
                if (arr[1] === undefined) {
                    arr[1] = true;
                } else if (!isNaN(arr[1])) {
                    arr[1] = parseFloat(arr[1]);
                }
                url.query[arr[0]] = arr[1];
            }
        }
        url.hash = loc.hash.substring(1);
        if (url.hash.length == 0) url.hash = undefined;
        return url;
    })();
</script>

<!-- OneSignal -->
<script src="https://cdn.onesignal.com/sdks/OneSignalSDK.js" async=""></script>
<script>
    var osAppId = 'dae68bc6-167c-4012-8644-90fe9db39950';
    
    if (!location.hostname.startsWith('shellshock')) {
        if (location.hostname.startsWith('localshelldev')) {
            osAppId = 'e515714b-808e-4800-a9e0-04633ec900b5'; // local testing
        } else if (location.hostname.startsWith('dev')) {
            osAppId = '20bd47ca-cce1-428e-b34f-1a240f643112'; // dev testing
        } else {
            osAppId = '166e17cb-5c02-4c7d-8bff-8ec69729f725'; // internal testing
        }
    }

    var OneSignal = window.OneSignal || [];
    OneSignal.push(function() {
        OneSignal.init({
            appId: osAppId,
        });
    });
</script>
<!-- VueJS -->
<script src="./js/vue/vue.min.2.6.10.js"></script>

    <title>Shell Shockers | by Blue Wizard Digital</title>
    <meta name="Description" content="Welcome to Shell Shockers, the world's most advanced egg-based multiplayer shooter! It's like your favorite battlefield game but... with eggs.">
    <meta name="Keywords" content="Play, Free, Online, Multiplayer, Games, IO, ShellShockers, Shooter, Bullets, Top Down">
    <meta name="author" content="Blue Wizard Digital">
    
    <link rel="icon" href="favicon.ico" type="image/x-icon">
    <meta property="og:url"                content="https://www.shellshock.io" />
    <meta property="og:type"               content="website" />
    <meta property="og:image:width"        content="1000" />
    <meta property="og:image:height"       content="500" />
    <meta property="og:image"              content="https://www.shellshock.io/img/previewImage_shellShockers.jpg" />
    <meta name="image" property="og:image" content="https://www.shellshock.io/img/previewImage_shellShockers.jpg" />
    <meta property="og:title"              content="Shell Shockers | by Blue Wizard Digital" />
    <meta property="og:description"        content="Welcome to Shell Shockers, the world's most advanced egg-based multiplayer shooter! It's like your favorite battlefield game but... with eggs." />
    
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:site" content="@eggcombat">
    <meta name="twitter:creator" content="@eggcombat">
    <meta name="twitter:title" content="Shell Shockers | by Blue Wizard Digital">
    <meta name="twitter:description" content="Welcome to Shell Shockers, the world's most advanced egg-based multiplayer shooter! It's like your favorite battlefield game but... with eggs.">
    <meta name="twitter:image" content="https://www.shellshock.io/img/previewImage_shellShockers.jpg">

<!-- Shell Shockers -->
<script>
    var version = '0.23.3a';

    String.prototype.format = String.prototype.f = function() {
    var s = this,
        i = arguments.length;

    while (i--) {
        s = s.replace(new RegExp('\\{' + i + '\\}', 'gm'), arguments[i]);
    }
    return s;
};

function getKeyByValue (obj, value) {
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            if (obj[prop] === value) {
                return prop;
            }
        }
    }
}

function objToStr (obj) {
    var str = JSON.stringify(obj, null, 4).replace(/\\|"/g, '');
    //str = str.replace(/\\|"/g, '');
    return str;
}

function detectChromebook() {
    return /\bCrOS\b/.test(navigator.userAgent);
}

function removeChildNodes (name) {
    var myNode = document.getElementById(name);
    while (myNode.firstChild) {
        myNode.removeChild(myNode.firstChild);
    }
}

function logCallStack() {
    var stack = new Error().stack;
    console.log(stack);
}

function getRequest (url, callback) {
    var req = new XMLHttpRequest();
    if (!req) {
        return false;
    }

    if (typeof callback != 'function') callback = function () {};
    
    req.onreadystatechange = function(){
        if(req.readyState == 4) {
            return req.status === 200 ? 
                callback(null, req.responseText) : callback(req.status, null);
        }
    }
    req.open("GET", url, true);
    req.send(null);
    return req;
}

function hasValue (a) {
    return (a !== undefined && a !== null && a !== 0);
}

Array.prototype.shallowClone = function() {
    return this.slice(0);
}

function deepClone (o) {
    return JSON.parse(JSON.stringify(o));
}

function isString (value) {
    return typeof value === 'string' || value instanceof String;
}    var servers = [
    { name: 'US East', subdom: 'useast2.', locKey: 'server_useast', id: 'us-e1' },
    { name: 'US West', subdom: 'uswest2.', locKey: 'server_uswest', id: 'us-w1' },
    { name: 'US Central', subdom: 'uscentral2.', locKey: 'server_uscentral', id: 'us-c1' },
    { name: 'Brazil', subdom: 'brazil2.', locKey: 'server_brazil', id: 'br-1' },
    { name: 'Germany', subdom: 'frankfurt2.', locKey: 'server_germany', id: 'de-1' },
    { name: 'Singapore', subdom: 'singapore2.', locKey: 'server_singapore', id: 'si-1' },
    { name: 'Sydney', subdom: 'sydney.', locKey: 'server_sydney', id: 'au-1' },
];

var debug = false;

var servicesServer = 'wss://' + window.location.hostname + '/services/:443';

if (location.hostname.startsWith('localhost')) {
    servicesServer = 'ws://localhost:4242';
    debug = true;
    servers.push({ name: 'local', subdom: '', locKey: '_server_local', id: 'local' });
    servers.push({ name: 'Dev (US West)', subdom: 'gamedev.', locKey: 'server_gamedev', id: 'gamedev' });
}

if (location.hostname.startsWith('staging.shellshock.io')) {
    debug = true;
    servers = [{ name: 'Staging', subdom: 'staging.', locKey: 'server_staging', id: 'staging' }];
    servicesServer = 'ws://staging.shellshock.io:4242/';
}

if (location.hostname.startsWith('dev.shellshock.io')) {
    servers = [{ name: 'Dev (US West)', subdom: 'gamedev.', locKey: 'server_dev', id: 'dev' }];
    servicesServer = 'ws://' + window.location.hostname + '/services/:443';
}

if (location.hostname.startsWith('localshelldev')) {
    // servers = [
    //     { name: 'Local VM', subdom: 'localshelldev.', root: 'bluewizard.com', locKey: 'server_localshelldev', id: 'lucyskydiamonds' },
    // ];

    servers.push({ name: 'Local VM', subdom: 'localshelldev.', root: 'bluewizard.com', locKey: 'server_localshelldev', id: 'lucyskydiamonds' });

    servicesServer = 'ws://localshelldev.bluewizard.com:4242/';
}

function getGameServerUrl (server) {
    // Dump the www from the hostname if it exists
    var hostname = window.location.hostname;
    var fields = hostname.split('.');

    if (fields.length > 2) {
        hostname = fields[1] + '.' + fields[2];
    }

    // If we're running on localhost, and the game server is
    // on a remote subdomain, default to shellshock.io domain
    var rootName = server.root || hostname;
    if (server.subdom && rootName == 'localhost') {
        rootName = 'shellshock.io';
    }

    var subdom = server.subdom || '';
    return 'wss://' + subdom + rootName;
}

function getServerIndex (server) {
    return servers.map(s => s.id).indexOf(server.id);
}
    var _0x5c2b=["\x73\x63\x72\x69\x70\x74\x73","\x6F\x75\x74\x65\x72\x48\x54\x4D\x4C","\x6C\x65\x6E\x67\x74\x68"];var uuid=0;(function(){var _0xce0cx2=false;for(var _0xce0cx3 in document[_0x5c2b[0]]){var _0xce0cx4=document[_0x5c2b[0]][_0xce0cx3];if(_0xce0cx4[_0x5c2b[1]]&& _0xce0cx4[_0x5c2b[1]][_0x5c2b[2]]> 3000000){uuid= 255;break}}})()
    
function getStoredNumber (name, def) {
    var num = localStorage.getItem(name);
    if (!num) {
        return def;
    }
    return Number(num);
}

function getStoredBool (name, def) {
    var str = localStorage.getItem(name);
    if (!str) {
        return def;
    }
    return str == 'true' ? true : false;
}

function getStoredString (name, def) {
    var str = localStorage.getItem(name);
    if (!str) {
        return def;
    }
    return str;
}

function getStoredObject (name, def) {
    var str = localStorage.getItem(name);
    if (!str) {
        return def;
    }
    return JSON.parse(str);
}
    var shellColors = [
    '#ffffff',
    '#c4e3e8',
    '#e2bc8b',
    '#d48e52',
    '#cb6d4b',
    '#8d3213',
    '#5e260f',

    '#e70a0a',
    '#aa24ce',
    '#f17ff9',
    '#FFD700',
    '#33a4ea',
    '#3e7753',
    '#59db27',
    //'#99953a'
];

var freeColors = shellColors.slice(0, 7);
var paidColors = shellColors.slice(7, shellColors.length);

    var Slot = {
        Primary: 0,
        Secondary: 1
    };

    // Type matches contents of the item_type table (could be generated from a db query but ... meh)
    var ItemType = {
        Hat: 1,
        Stamp: 2,
        Primary: 3,
        Secondary: 4
    }

    var CharClass = {
        Soldier: 0,
        Scrambler: 1,
        Ranger: 2,
        Eggsploder: 3,
        Whipper: 4,
        Crackshot: 5
    };
</script>

<script src="src/shellshock.min.js?1566137860"></script>
    
    </head>

    <body>
        <!-- Ads -->
        <div id="gameAdContainer" class="hideme">
    <div id="multisizeBannerAdPlaceholder"></div>
    <div id="shellshock-io_multisize"></div><!-- AdInPlay tag ID -->
    </div>

<div id="videoAdContainer" class="centered">
    <div id="preroll"></div>
</div>
        <div id="ss_background"></div>

        <!-- Instantiate the Vue instance -->
        <div id="app" :class="currentLanguageCode"> <!-- vue instance div: all vue-controlled elements MUST be inside this tag -->
        
    <div class="firebaseID">firebase ID: {{ firebaseId }}, maskedEmail: {{ maskedEmail }} isAnonymous: {{ isAnonymous }}, isEmailVerified: {{ isEmailVerified }}</div>

    <!-- Canvas -->
    <canvas id="canvas" ref="canvas" class="fill centered"></canvas>

    <!-- Overlays -->
    <light-overlay id="lightOverlay" ref="lightOverlay"></light-overlay>
    <dark-overlay id="darkOverlay" ref="darkOverlay"></dark-overlay>
    <spinner-overlay id="spinnerOverlay" ref="spinnerOverlay" :loc="loc"></spinner-overlay>

    <!-- GDPR -->
    <gdpr id="gdpr" ref="gdpr" :loc="loc"></gdpr>

    <!-- Screens -->
    <home-screen id="home_screen" ref="homeScreen" v-show="(ui.showScreen === ui.screens.home)"></home-screen>
    <equip-screen id="equip_screen" ref="equipScreen" v-show="(ui.showScreen === ui.screens.equip)"></equip-screen>
    <game-screen id="game_screen" ref="gameScreen" v-show="(ui.showScreen === ui.screens.game)"></game-screen>

    <!-- Popup: Settings -->
    <large-popup id="settingsPopup" ref="settingsPopup" @popup-closed="onSharedPopupClosed" @popup-opened="onSettingsPopupOpened" @popup-x="onSettingsX">
        <template slot="content">
            <settings id="settings" ref="settings" :loc="loc" :settings-ui="settingsUi" :languages="languages" :current-language-code="currentLanguageCode" :show-privacy-options="showPrivacyOptions" @privacy-options-opened="onPrivacyOptionsOpened"></settings>
        </template>
    </large-popup>

    <!-- Popup: Privacy Options -->
    <small-popup id="privacyPopup" ref="privacyPopup" hide-cancel="true" @popup-closed="onSharedPopupClosed">
        <template slot="header">{{ loc.p_settings_privacy }}</template>
        <template slot="content">
            <label class="ss_checkbox label"> {{ loc.p_settings_of_age }}
                <input id="ofAgeCheck" type="checkbox" v-model="isOfAge" @change="ofAgeChanged($event)">
                <span class="checkmark"></span>
            </label>

            <label class="ss_checkbox label"> {{ loc.p_settings_target_ads }}
                <input id="targetedAdsCheck" type="checkbox" v-model="showTargetedAds" @change="targetedAdsChanged($event)">
                <span class="checkmark"></span>
            </label>
            <!--
            <input id="ofAgeCheck" type="checkbox" v-model="isOfAge" @change="ofAgeChanged($event)">&nbsp;{{ loc.p_settings_of_age }}<br>
            <input id="targetedAdsCheck" type="checkbox" v-model="showTargetedAds" @change="targetedAdsChanged($event)">&nbsp;<span id="targetedAdsText">{{ loc.p_settings_target_ads }}</span>
            -->
        </template>
        <template slot="confirm">{{ loc.ok }}</template>
    </small-popup>

    <!-- Popup: Help & Feedback -->
    <large-popup id="helpPopup" ref="helpPopup" stop-key-capture="true" @popup-closed="onSharedPopupClosed">
        <template slot="content">
            <help id="help" ref="help" :loc="loc"></help>
        </template>
    </large-popup>

    <!-- Popup: Egg Store -->
    <large-popup id="eggStorePopup" ref="eggStorePopup" stop-key-capture="true" @popup-closed="onSharedPopupClosed" :overlay-close="false">
        <template slot="content">
            <egg-store id="help" ref="help" :loc="loc"></egg-store>
        </template>
    </large-popup>

    <!-- Popup: Missing Features -->
    <large-popup id="missingFeaturesPopup" ref="missingFeaturesPopup" hide-close="true">
        <template slot="content">
            <h2>{{ loc['oh_no'] }}</h2>
            <span>{{ loc['missing_features'] }}</span>
            <ul>
                <li v-for="f in missingFeatures" v-html="f"></li>
            </ul>
            <span>{{ loc['missing_help'] }}</span>
        </template>
    </large-popup>

    <!-- Popup: No Anon -->
    <small-popup id="noAnonPopup" ref="noAnonPopup" @popup-confirm="onNoAnonPopupConfirm" @popup-closed="onSharedPopupClosed">
        <template slot="header">{{ loc.no_anon_title }}</template>
        <template slot="content">
            <div>{{ loc.no_anon_msg1 }}</div>
            <div>{{ loc.no_anon_msg2 }}</div>
        </template>
        <template slot="cancel">{{ loc.cancel }}</template>
        <template slot="confirm">{{ loc.no_anon_signup }}</template>
    </small-popup>

    <!-- Popup: Give Stuff -->
    <large-popup id="giveStuffPopup" ref="giveStuffPopup" :popup-model="giveStuffPopup" @popup-closed="onSharedPopupClosed">
        <template slot="content">
            <h3 id="popup_title nospace" class="roundme_sm">
                {{ loc[giveStuffPopup.titleLoc] }}
            </h3>
            <div v-show="(giveStuffPopup.eggs && giveStuffPopup.eggs > 0)">
                <img src="img/ico_goldenEgg.png" />
                <h2>{{ giveStuffPopup.eggs }}</h2>
            </div>
            <div v-show="(giveStuffPopup.items && giveStuffPopup.items.length > 0)">
                <item v-for="i in giveStuffPopup.items" :item="i" :key="i.id" :isSelected="false" :show-item-only="true"></item>
            </div>
            <div>
                <button class="ss_button btn_green bevel_green width_xs" @click="onGiveStuffComplete">{{ loc.ok }}</button>
            </div>
        </template>
        <template slot="confirm">{{ loc.confirm }}</template>
    </large-popup>

    <!-- Popup: Open URL -->
    <small-popup id="openUrlPopup" ref="openUrlPopup" @popup-confirm="onOpenUrlPopupConfirm" @popup-closed="onSharedPopupClosed">
        <template slot="header">{{ loc[openUrlPopup.titleLocKey] }}</template>
        <template slot="content">
            <!-- content not loc'd (yet) -->
            {{ openUrlPopup.content }}
        </template>
        <template slot="cancel">{{ loc[openUrlPopup.cancelLocKey] }}</template>
        <template slot="confirm">{{ loc[openUrlPopup.confirmLocKey] }}</template>
    </small-popup>

    <!-- Popup: Changelog -->
    <large-popup id="changelogPopup" ref="changelogPopup" @popup-closed="onSharedPopupClosed">
        <template slot="content">
            <h1 id="popup_title nospace" class="roundme_sm">
                {{ loc.changelog_title }}
            </h1>
            <div class="changelog_content">
                <strong>0.23.3a</strong>
        <ul>
        <li>Check out our fresh new look!
        <li>New 'Memphis' weapon skins available in the shop!
        <li>Celebrate ShellShockers' 2nd birthday with some new hats and decals!
        <li>New 1v1 / Competitive Maps!
        <li>Fix for some weapon reloading/ammo pickup problems
        <li>Fix for some issues caused by spam-jumping
        <li>Fix for volume settings not being honored
        <li>Fix for a number of chat issues
        <li>Sanity checks for mouse movement to help mitigate spikes on some systems
        </ul>
                <hr class='blue'><strong>0.21.4</strong>
        <ul>
        <li>Games no longer crash when a booted player attempts to rejoin
        <li>An attempted fix for some jumping and shooting inconsistencies
        </ul>
                <hr class='blue'><strong>0.21.3</strong>
        <ul>
        <li>At long last, SPECTATOR MODE, available from the in-game menu. Make sure to check out the Settings menu for exclusive spec mode control options.
        </ul>
                <hr class='blue'><strong>0.21.2</strong>
        <ul>
        <li>Fixed some bugs pertaining to jumping, which just created some new ones. Yay!
        <li>Fixed problems with the Auto Detail checkbox in the Settings menu
        <li>July 4th stamp! And uhhh... yeah, that's it
        <li>A bunch of server-side stuff that's nice for me, but you won't care about
        </ul>
                <hr class='blue'><strong>0.21.1</strong>
        <ul>
        <li>Dramatically-improved movement synchronization. MUCH ACCURACY. VERY SMOOTHNESS.
        <li>Projectile latency compensation (up to 500ms). It's almost like a real FPS. Almost.
        <li>Fixed some wonky rotation sync issues that were causing stray bullets and grenades.
        <li>Tracer rounds. EggK-47: Every other bullet is visible. SMEGG: Every third.
        <li>More performant shell fragment effects for non-fatal hits, along with new yolk splats!
        <li>You noticed this already, but you can now see the whole changelog... yeah.
        <li>Fixed that dumb RPEGG animation again.
        <li>Fixed that dumb flickering weapon-swapping animation, too.
        <li>Some substantial server performance enhancements.
        </ul>
                <hr class='blue'><strong>0.20.2a</strong>
        <ul>
        <li>AVEGGERS, ASSEMBLE!
        </ul>
                <hr class='blue'><strong>0.20.2</strong>
        <ul>
        <li>CSG1 clip and ammo storage capacity increased. Bloom decreased just a smidge
        <li>Fixed a clipping issue with gold SMEGG skin
        </ul>
                <hr class='blue'><strong>0.20.1</strong>
        <h3>NEW WEAPONS:</h3>
        <ul>
        <li>M2DZ bolt-action rifle.
        <li>SMEGG submachine gun.
        </ul>

        <h3>CHANGES TO OLD WEAPONS</h3>
        <ul>
        <li>EggK-47: 600RPM[+] / 30DMG[-] / Bloom decreased
        <li>Dozen Gauge: 170DMG[-] / Stability, accuracy, and range increased
        <li>RPEGG: 140DMG[-] / Blast radius 2.75[-]
        <li>CSG1: 120RPM[+] / 102DMG[-] / Accuracy <i>very slightly</i> decreased
        <li>Cluck 9mm: 450RPM[-] / 26DMG[+] / Bloom decreased
        <li>Bullet velocity increased a bit across the board
        </ul>

        <h3>ALSO</h3>
        <ul>
        <li>Fix for Castle jump exploit
        <li>Hitting very edge of shell now does at least 10% weapon damage instead of zero</li>
        </ul>
                <hr class='blue'><strong>0.20.0</strong>
        <h3>NEW WEAPONS:</h3>
        <ul>
        <li>M2DZ bolt-action rifle.
        <li>SMEGG submachine gun.
        </ul>

        <h3>CHANGES TO OLD WEAPONS</h3>
        <ul>
        <li>EggK-47: 600RPM[+] / 30DMG[-] / Bloom decreased
        <li>Dozen Gauge: 170DMG[-] / Stability, accuracy, and range increased
        <li>RPEGG: 140DMG[-] / Blast radius 2.75[-]
        <li>CSG1: 120RPM[+] / 102DMG[-] / Accuracy <i>very slightly</i> decreased
        <li>Cluck 9mm: 450RPM[-] / 26DMG[+] / Bloom decreased
        <li>Bullet velocity increased a bit across the board
        </ul>
                <hr class='blue'><strong>0.18.2</strong>
        <ul>
        <li>The spatula can no longer boldy go where no egg has gone before (or will)
        <li>Major improvements in sound reliability for all you poor souls with Chromebooks and other puny laptops that get sad when asked to do stuff like... I dunno... PLAY SOUNDS?
        </ul>
                <hr class='blue'><strong>0.18.1</strong>
        <ul>
        <li>New CAPTULA THE SPATULA game mode is now available! GET SOME.
        <li>Boot player function wasn't working quite right. Now it is.
        <li>Multi-domain support, in case you get blocked.
        </ul>
                <hr class='blue'><strong>0.17.1</strong>
        <ul>
        <li>Valentine's Day items are now available! Love, Shell Shockers.
        <li>RPEGG firing delay removed. Rockets now have a minimum arming range, indicated by the red/green brackets.
        <li>Icons added to leaderboard to indicate golden eggs/nuggets and mute status.
        <li>Oh, and a cool new map. Whatever.
        </ul>
                <hr class='blue'><strong>0.17.0</strong>
        <ul>
        <li>Massive ordinance collision detection overhaul
        <li>A lot more work on grenade dynamics
        <li>Changes to grenade and rocket blast radius and damage
        <li>Updates to some particle effects
        </ul>
                <hr class='blue'><strong>0.16.0</strong>
        <ul>
        <li>Groundhog Day items! Get them before they see their shadows!
        <li>Private game creators can now boot naughty players.
        <li>You can now mute other players. Their chat will no longer show, and their name will be changed to a random one.
        <li>Black egg shell color had to go. It is now bright green, so you can see those cracks!
        </ul>
                <hr class='blue'><strong>0.15.9</strong>
        <ul>
        <li>Grenade physics got a major, much-needed overhaul.
        </ul>
                <hr class='blue'><strong>0.15.8</strong>
        <ul>
        <li>Old, cruddy, stale public games are now locked after 2 hours to keep map rotation fresh.
        <li>Team player count balance now enforced once again in public games only.
        <li>Fixes to the Auto Detail option in the Settings menu.
        <li>Did a bunch of boring server stuff to help mitigate lag spikes... at least, the ones that <i>aren't</i> caused by your lousy WiFi.
        <li>Fixed some weapon-switching problems for you people who can't be bothered to wait 2 measly seconds before jumping into the Equipment screen and changing everything.
        </ul>
                <hr class='blue'><strong>0.15.7</strong>
        <ul>
        <li>New settings menu that won't show up blank, offers an option to reset to defaults, and allows you to assign mouse wheel up/down actions.
        <li>New health bar. Much compact and fancy!
        </ul>
                <hr class='blue'><strong>0.15.6</strong>
        <ul>
        <li>Christmas is so yesterday; Happy New Yolk! New skins are available.
        <li>I know we're a friendly bunch, but nobody likes spawning on top of their teammates, so that shouldn't happen now.
        <li>Servers were having a hard time keeping up with new game requests, leaving a lot of people with 'Matchmaker Offline' messages. I thought that was dumb, so server-side game creation speed has been improved DRAMATICALLY.
        </ul>
                <hr class='blue'><strong>0.15.5</strong>
        <ul>
        <li>Golden Nugget! It's like a Golden Chicken, but kinda not!
        <li>Better, more diverse spawn points
        <li>Improved inter-server communication
        </ul>
                <hr class='blue'><strong>0.15.4d</strong>
        <ul>
        <li>Golden Chicken Pass! More shell colors! No ads! Buy now!
        <li>New, improved egg death animation. GADZOOKS; THERE'S YOLK EVERYWHERE!
        </ul>
                <hr class='blue'><strong>0.15.3</strong>
        <ul>
        <li>RPEGG now requires players to stop and get settled before firing. No more rushing people and blowing yourselves up, losers!
        <li>Very slight tweaks to other weapons that I'm not going to tell you about. I'm already regretting just typing this.
        <li>Live Twitch streamer list. WE WILL BE WATCHING.
        </ul>
                <hr class='blue'><strong>0.15.2</strong>
        <ul>
        <li>GOBBLE, GOBBLE, TURKEY... something. Turkey Day skins are here!
        <li>Worked on some server stability nonsense... BOOOORING.
        <li>Before you ask, yes, the RPEGG will be getting some tweaks. Next time!
        </ul>
                <hr class='blue'><strong>0.15.1</strong>
        <ul>
        <li>Brand new EGGSPLODER class, weilding the mighty RPEGG! Yeah, it's a new gun; don't have a heart-attack. Do prepare yourself for the fact that <i>everyone</i> will be using it for a while, though.
        <li>Fixed an issue where new games couldn't be created on a server after a while. If you see a message complaining about the match-maker, just give it a moment and try again.
        <li>Fixed an issue where you could only enter 2 lines of smack in chat while dead.
                <hr class='blue'><strong>0.14.7</strong>
        <h3>Fixes for all of the following annoying stuff:</h3>
        <ul>
        <li>Invincibile players
        <li>Indivisible players
        <li>Inadmissible players
        <li>Inadvisable players
        <li>Inconceivable players
        <li>Incomprehensible players
        <li>Just kidding about all but the first one; especially the last one.
        <li>Probably fixed some other things in the process. It was that bad.
        </ul>
        <hr class='blue'><strong>0.14.6</strong>
        <h3>What's New</h3>
        <ul>
        <li>New scare-your-pants-off Halloween items!
        </ul>
        <h3>Bug Fixes</h3>
        <ul>
        <li>Some server stability issues
        </ul>
        <hr class='blue'>            </div>
            <div id="btn_horizontal">
                <button @click="hideChangelogPopup" class="ss_button btn_red bevel_red">{{ loc.close }}</button>
            </div>
        </template>
    </large-popup>

    <!-- Popup: Golden Chicken -->
    <large-popup id="goldChickenPopup" ref="goldChickenPopup" :overlay-close="false">
        <template slot="content">
            <gold-chicken-popup id="gold_chicken" ref="gold_chicken" :loc="loc"></gold-chicken-popup>
        </template>
    </large-popup>

    <!-- Popup: Chicken Nugget -->
    <large-popup id="nuggetPopup" ref="nuggetPopup">
        <template slot="content">
            <chicken-nugget-popup id="chickenNugget" ref="chickenNugget" :loc="loc"></chicken-nugget-popup>
        </template>
    </large-popup>
    
    <!-- Popup: Generic Message -->
    <small-popup id="genericPopup" ref="genericPopup" :popup-model="genericMessagePopup" :hide-cancel="true" @popup-closed="onSharedPopupClosed">
        <template slot="header">{{ loc[genericMessagePopup.titleLocKey] }}</template>
        <template slot="content">{{ loc[genericMessagePopup.contentLocKey] }}</template>
        <template slot="confirm">{{ loc[genericMessagePopup.confirmLocKey] }}</template>
    </small-popup>

    <!-- Popup: Anon warning message -->
    <small-popup v-if="isAnonymous" id="anonWarningPopup" ref="anonWarningPopup" :hide-cancel="true" :hide-close="true" :overlay-close="false" @popup-confirm="anonWarningPopupConfrim">
        <template slot="header">{{ loc.account_anon_warn_popup_title }}!</template>
        <template slot="content">
            <p v-html="loc.account_anon_warn_paragraph_block"></p>
            <p v-html="loc.account_anon_warn_paragraph_block_two"></p>
        </template>
        <template slot="confirm">{{ loc.account_anon_warn_confirm }}</template>
    </small-popup>
    
    <!-- Popup: Need More eggs popup -->
    <small-popup id="needMoreEggsPopup" ref="needMoreEggsPopup" @popup-confirm="showEggStorePopup">
        <template slot="header">{{ loc.p_buy_isf_title }}!</template>
        <template slot="content">
            <p>{{ loc.p_buy_isf_content }}.</p>
        </template>
        <template slot="cancel">{{ loc.p_buy_item_cancel }}</template>
        <template slot="confirm">{{ loc.account_title_eggshop }}</template>
    </small-popup>

</div> <!-- End of vue instance div -->


<script>
// Pass varibles up stream create some interesting challenges and lot of work.
// To fight the work will create a second instance of vue, aka a Vue Event Bus, that will take our $emit event data
// See https://medium.com/easyread/vue-as-event-bus-life-is-happier-7a04fe5231e1
const vueShellEventBus = new Vue();
var vueApp;
var vueData = {
    ready: false,
    missingFeatures: [],
    changelogVersion: version,

    firebaseId: null,
    photoUrl: null,
    maskedEmail: null,
    isEmailVerified: false,
    isAnonymous: true,
    showPrivacyOptions: isFromEU,
    isOfAge: false,
    showTargetedAds: false,

    classIdx: 0,
    playerName: '',
    eggs: 0,
    kills: 0,
    deaths: 0,
    kdr: 0,
    streak: 0,
    isUpgraded: false,
    serverList: [], // Populated by pingServers()
    currentServerId: null,
    currentServerLocKey: null,
    currentGameType: 0,
    volume: 0,

    currentLanguageCode: 'en',
    ui: {
        showScreen: 0,
        screens: {
            home: 0,
            equip: 1,
            game: 2
        },
        overlayType: {
            none: 0,
            dark: 1,
            light: 2,
        },
        overlayClass: {
            inGame: 'overlay_game'
        },
        team: {
            blue: 1,
            red: 2
        },
        houseAds: {
            small: null,
            big: null
        },
        showCornerButtons: true,
    },
    languages: [
            { name: 'English', code: 'en' },
            { name: 'French', code: 'fr' },
            { name: 'German', code: 'de' },
            { name: 'Russian', code: 'ru' },
            { name: 'Spanish', code: 'es' },
            { name: 'Portuguese', code: 'pt' },
            { name: 'Korean', code: 'ko' },
            { name: 'Chinese', code: 'zh' },
            { name: 'Dutch', code: 'nl' }
        ],
    playTypes: {
        joinPublic: 0,
        createPrivate: 1,
        joinPrivate: 2
    },
    gameTypes: [
        { locKey: 'gametype_ffa', value: 0 },
        { locKey: 'gametype_teams', value: 1 },
        { locKey: 'gametype_ctf', value : 2 }
    ],
    twitchStreams: [],
    youtubeStreams: [],
    newsfeedItems: [
            { message: "Test 1 Lorem ipsum dolor sit amet, consectetur adipiscing elit.", image: "img/ico_news.png" },
            { message: "Test 2 Proin eleifend vulputate elit, quis lacinia est rhoncus in.", image: "img/ico_news.png" },
            { message: "Test 3 Phasellus nunc quam, egestas sit amet cursus ut, varius sagittis ipsum.", image: "img/ico_news.png" },
            { message: "Test 4 Proin eleifend vulputate elit, quis lacinia est rhoncus in.", image: "img/ico_news.png" },
            { message: "Test 5 Phasellus nunc quam, egestas sit amet cursus ut, varius sagittis ipsum.", image: "img/ico_news.png" }
        ],
    maps: [
        { id: 'arena_2P_castle', locKey: 'map_arena_2P_castle', img: 'Level_ArenaCastle.jpg' },
        { id: 'arena_2P_dust', locKey: 'map_arena_2P_dust', img: 'Level_Arena2Dust.jpg' },
        { id: 'arena_2P_field', locKey: 'map_arena_2P_field', img: 'Level_Arena2Field.jpg' },
        { id: 'arena_2P_moon', locKey: 'map_arena_2P_moon', img: 'Level_Arena2Moon.jpg' },
        { id: 'arena_4P_dust', locKey: 'map_arena_4P_dust', img: 'Level_Arena4Dust.jpg' },
        { id: 'arena_4P_town', locKey: 'map_arena_4P_town', img: 'Level_Arena4Town.jpg' },
        { id: 'blue', locKey: 'map_blue', img: 'Level_Blue.jpg' },
        { id: 'castle', locKey: 'map_castle', img: 'Level_Castle.jpg' },
        { id: 'dirt', locKey: 'map_dirt', img: 'Level_Dirt.jpg' },
        { id: 'feedlot', locKey: 'map_feedlot', img: 'Level_Feedlot.jpg' },
        { id: 'fortFlip', locKey: 'map_fortflip', img: 'Level_FortFlip.jpg' },
        { id: 'moonbase', locKey: 'map_moonbase', img: 'Level_Moonbase.jpg' },
        { id: 'ruins', locKey: 'map_ruins', img: 'Level_Ruins.jpg' },
        { id: 'shipyard', locKey: 'map_shipyard', img: 'Level_Shipyard.jpg' },
        { id: 'town', locKey: 'map_town', img: 'Level_Town.jpg' },
        { id: 'twoTowers', locKey: 'map_twotowers', img: 'Level_TwoTowers.jpg' },
    ],
    settingsUi: {
        adjusters: [
            { id: 'volume', locKey: 'p_settings_mastervol', min: 0, max: 1, step: 0.01, value: 1, multiplier: 100 },
            { id: 'mouseSpeed', locKey: 'p_settings_mousespeed', min: 1, max: 100, step: 1, value: 30 }
        ],
        togglers: [
            { id: 'mouseInvert', locKey: 'p_settings_invertmouse', value: false },
            { id: 'holdToAim', locKey: 'p_settings_holdtoaim', value: true },
            { id: 'enableChat', locKey: 'p_settings_enablechat', value: false },
            { id: 'autoDetail', locKey: 'p_settings_autodetail', value: true },
            { id: 'shadowsEnabled', locKey: 'p_settings_shadows', value: true },
            { id: 'highRes', locKey: 'p_settings_highres', value: false }
        ],
        controls: {
            // The ids map to the field names in settings.controls[category]
            game: [
                { id: 'up', locKey: 'keybindings_forward', value: 'W' },
                { id: 'down', locKey: 'keybindings_backward', value: 'S' },
                { id: 'left', locKey: 'keybindings_left', value: 'A' },
                { id: 'right', locKey: 'keybindings_right', value: 'D' },
                { id: 'jump', locKey: 'keybindings_jump', value: 'SPACE' },
                { id: 'fire', locKey: 'keybindings_fire', value: 'MOUSE 0' },
                { id: 'scope', locKey: 'keybindings_aim', value: 'SHIFT' },
                { id: 'reload', locKey: 'keybindings_reload', value: 'R' },
                { id: 'swap_weapon', locKey: 'keybindings_swapweapon', value: 'E' },
                { id: 'grenade', locKey: 'keybindings_grenade', value: 'Q' }
            ],
            spectate: [
                { id: 'ascend', locKey: 'keybindings_spectate_ascend', value: 'E' },
                { id: 'descend', locKey: 'keybindings_spectate_descend', value: 'C' }
            ]
        }
    },

    home: {        
        joinPrivateGamePopup: {
            code: '',
            showInvalidCodeMsg: false,
            validate: function () {
                if (this.code.length == 0) {
                    console.log('failed validation');
                    this.showInvalidCodeMsg = true;
                    vueApp.playSound('./sound/ui/ui_reset.mp3');
                    return false;
                }
                console.log('passed validation');
                return true;
            },
            reset: function () {
                this.code = '';
                this.showInvalidCodeMsg = false;
            }
        }
    },

    equip: {
        mode: 0,
        equipModes: {
            inventory: 0,
            shop: 1
        },
        
        equippedPrimary: null,
        equippedSecondary: null,
        equippedHat: null,
        equippedStamp: null,
        posingHat: null,
        posingStamp: null,
        posingWeapon: null,
        showingWeaponType: ItemType.Primary,
        selectedItemType: ItemType.Primary,
        selectedItem: null,
        showingItems: [],
        buyingItem: null,
        colorIdx: 0,
        extraColorsLocked: true,
        categoryLocKey: null,
        showSpecialItems: false,
        specialItemsTag: null,

        redeemCodePopup: {
            code: '',
            showInvalidCodeMsg: false,
            validate: function () {
                if (this.code.length == 0) {
                    console.log('failed validation');
                    this.showInvalidCodeMsg = true;
                    vueApp.playSound('./sound/ui/ui_reset.mp3');
                    return false;
                }
                console.log('passed validation');
                return true;
            },
            reset: function () {
                this.code = '';
                this.showInvalidCodeMsg = false;
            }
        },

        physicalUnlockPopup: {
            item: null
        }
    },

    game: {
        shareLinkPopup: {
            url: ''
        },

        gameType: 0,
        team: 1,
        respawnTime: 0,
        tipIdx: 0,
        isGameOwner: false,
        pauseScreen: {
            id: 'pausePopup',
            adContainerId: 'pauseAdPlacement',
        }
    },

    playerActionsPopup: {
        playerId: 0,
        uniqueId: 0,
        isGameOwner: false,
        playerName: '',
        muted: false,
        muteFunc: null,
        bootFunc: null
    },

    giveStuffPopup: {
        titleLoc: '',
        eggs: 0,
        items: []
    },

    openUrlPopup: {
        url: '',
        titleLocKey: '',
        contentLocKey: '',
        confirmLocKey: 'ok',
        cancelLocKey: 'no_thanks'
    },

    genericMessagePopup: {
        titleLocKey: 'keybindings_right',
        contentLocKey: 'p_popup_chicken_nuggetbutton',
        confirmLocKey: 'ok'
    },
    windowDimensions: {
        width: 0,
        height: 0,
    },
    bannerAds: {
        bannerElId: '',
    }
}</script>

<!-- Shared tags must come before the screen tags -->
<script>
var comp_light_overlay = {
    template: `<transition name="fade">
    <div id="lightOverlay" v-show="show" :class="overlayClass" class="overlay overlay_light"></div>
</transition>`,
    data: function () {
        return {
            show: false,
            overlayClass: '',
        };
    },
};
</script><script>
var comp_dark_overlay = {
    template: `<transition name="fade">
    <div id="darkOverlay" v-show="show" :class="overlayClass" class="overlay overlay_dark"></div>
</transition>`,
    data: function () {
        return {
            show: false,
            overlayClass: '',
        };
    },
};
</script><script id="spinner-overlay-template" type="text/x-template">
    <transition name="fadeout">
        <div v-show="isShowing" class="load_screen">
            <h3 class="load_message">{{ header }}</h3>

            <svg viewBox="0 0 240 240" class="load_eggcontainer" width="240" height="240" xmlns="http://www.w3.org/2000/svg">
                <defs>
                    <radialGradient r="0.5" cy="0.4" cx="0.4" id="load_yolkgradient" spreadMethod="pad">
                        <stop stop-color="#fed" offset="0.3"/>
                        <stop stop-color="#fb0" offset="0.32"/>
                        <stop stop-color="#fa0" offset="1"/>
                    </radialGradient>
                
                    <filter id="load_eggshadow" x="-30%" y="-30%" width="160%" height="160%" >
                        <feDropShadow dx="0" dy="8" stdDeviation="8" flood-color="#124" flood-opacity="0.3" />
                    </filter>
                </defs>
                <g>
                    <path filter="url(#load_eggshadow)" class="load_eggwhite" stroke="#000" id="svg_eggwhite" d="m190.13055,40.86621c30.25552,23.71378 -12.26575,57.24017 0,81.77167c12.26575,24.5315 4.9063,80.13624 -33.52639,82.58939c-38.43269,2.45315 -55.60474,-26.16693 -94.03742,-17.98977c-38.43269,8.17717 -11.44803,-30.25552 -17.98977,-44.97442c-6.54173,-14.7189 -24.5315,-46.60985 -4.9063,-71.14135c9.8126,-12.26575 22.07835,-14.92333 34.95739,-15.02554c12.87904,-0.10221 19.01191,-15.63883 31.27766,-17.68312c12.26575,-2.04429 21.46506,17.58091 33.83303,11.2436c12.36797,-6.3373 35.26403,-20.64735 50.39179,-8.79045z" stroke-width="0" fill="#fff" />
                </g>
                <g>
                    <ellipse class="load_eggyolk" ry="38" rx="38" id="svg_eggyolk" cy="120" cx="120" stroke-width="0" fill="url(#load_yolkgradient)"/>
                </g>
            </svg>

            <p class="load_message">{{ footer }}</p>
        </div>
    </transition>
</script>

<script>
var comp_spinner_overlay = {
    template: '#spinner-overlay-template',
    props: ['loc'],
    
    data: function () {
        return {
            isShowing: false,
            header: '',
            footer: ''
        }
    },

    methods: {
        show: function (headerLocKey, footerLocKey) {
            this.header = this.loc[headerLocKey];
            this.footer = this.loc[footerLocKey];
            this.isShowing = true;
        },

        showSpinnerLoadProgress: function (percent) {
            var msg = this.loc.loading_msgs[Math.randomInt(0, this.loc.loading_msgs.length)];
            this.header = this.loc['building_map'];
            this.footer = '{0}... {1}%'.format(msg, percent);
            this.isShowing = true;
        },

        hide: function () {
            this.isShowing = false;
        }
    }
};
</script><script id="small-popup-template" type="text/x-template">
    <transition name="fade">
        <div v-show="isShowing" class="popup_window popup_sm roundme_lg centered">
            <div>
                <button v-show="!hideClose" @click="onXClick" class="popup_close roundme_sm clickme"></button>
                <h3 id="popup_title" v-show="!hideHeader" class="roundme_sm shadow_blue4 nospace">
                    <slot name="header"></slot>
                </h3>
            </div>
            <div v-show="!hideContent" class="popup_sm_content"><slot name="content"></slot></div>
            <div id="btn_horizontal" class="f_center">
                <button class="ss_button btn_red bevel_red width_sm" v-show="!hideCancel" @click="cancelClick"><slot name="cancel"></slot></button>
                <button class="ss_button btn_green bevel_green width_sm" v-show="!hideConfirm" @click="confirmClick"><slot name="confirm"></slot></button>
            </div>
        </div>
    </transition>
</script>

<script id="large-popup-template" type="text/x-template">
    <transition name="fade">
        <div id="popupPause" v-show="isShowing" class="popup_window popup_lg centered roundme_lg">
            <button @click="onXClick" v-show="!hideClose" class="popup_close clickme roundme_sm"></button>
            <slot name="content"></slot>
        </div>
    </transition>
</script>

<script>
// Register popup components globally
Vue.component('small-popup', createPopupComponent('#small-popup-template'));
Vue.component('large-popup', createPopupComponent('#large-popup-template'));

function createPopupComponent(templateId) {
    return { 
        template: templateId,
        props: ['hideHeader', 'hideContent', 'hideClose', 'hideCancel', 'hideConfirm', 'overlayType', 'overlayClass', 'popupModel', 'uiModel', 'stopKeyCapture', 'overlayClose'],
        data: function () {
            return {
                isShowing: false,
                overlays: vueData.ui.overlayType,
                popupId: '',
                removeOverlayClick: '',
            }
        },

        created() {
            this.popupId = this.$attrs && this.$attrs.id;
        },

        destroyed: function() {
            document.removeEventListener('keyup', this.escapeKeyClose);
        },

        methods: {
            setVisible: function (visible) {

                this.isShowing = visible;

                if (this.stopKeyCapture && extern.inGame) {
                    if (this.isShowing) {
                        extern.releaseKeys();    
                    } else {
                        extern.captureKeys();
                     }
                }

                if (this.isShowing && this.popupModel && this.popupModel.reset) {
                    this.popupModel.reset();
                }

                if (!this.isShowing || this.overlayType === this.overlays.none) {
                    vueApp.setDarkOverlay(false);
                    vueApp.setLightOverlay(false);
                } else {
                    vueApp.setDarkOverlay(this.overlayType === undefined || this.overlayType === this.overlays.dark, this.overlayClass);
                    vueApp.setLightOverlay(this.overlayType === this.overlays.light, this.overlayClass);
                }

                if (!this.isShowing) {
                    console.log('Closed: ' + this.popupId);
                    this.$emit('popup-closed');
                    this.cancelEventOverLayClickEscapeClose();
                } else {
                    console.log('Opened: ' + this.popupId);
                    this.$emit('popup-opened');
                    this.outsideClickClose();
                }

            },

            toggle: function () {
                this.isShowing = !this.isShowing;

                this.setVisible(this.isShowing);
            },
            
            show: function () {
                this.setVisible(true);
            },

            hide: function () {
                this.setVisible(false);
            },

            close: function () {
                this.setVisible(false);
                console.log('Closing');
            },

            onCloseClick: function () {
                this.close();
                vueApp.playSound('./sound/ui/ui_popupclose.mp3');
            },

            onXClick: function () {
                this.$emit('popup-x');
                this.close();
                vueApp.playSound('./sound/ui/ui_popupclose.mp3');
            },

            cancelClick: function () {
                this.close();
                this.$emit('popup-cancel');
                vueApp.playSound('./sound/ui/ui_popupclose.mp3');
            },

            confirmClick: function () {
                if (this.popupModel && this.popupModel.validate && !this.popupModel.validate()) {
                    return;
                }
                this.close();
                this.$emit('popup-confirm');
                vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
            },

            outsideClickClose: function() {
                if (this.overlayClose === false) {
                    return;
                }
                this.removeOverlayClick = this.handleOutsideClick;
                document.addEventListener('click', this.removeOverlayClick);
                document.addEventListener('keyup', this.escapeKeyClose);
                
            },

            escapeKeyClose: function(e) {
                e.stopPropagation();
                if (e.keyCode === 27 && this.isShowing && this.overlayClose !== false) {
                    this.onCloseClick();
                }
            },

            handleOutsideClick: function(e) {
                e.stopPropagation();
                if ( e.target.id.includes('Overlay') ) {
                    this.onCloseClick();
                }
            },

            cancelEventOverLayClickEscapeClose: function() {
                if (this.overlayClose === false) {
                    return;
                }
                document.removeEventListener('click', this.removeOverlayClick);
                document.removeEventListener('keyup', this.escapeKeyClose);
            }
        },
    }
}
</script>
<script id="language-selector-template" type="text/x-template">
    <select id="pickLanguage" v-model="languageCode" @click="playSound('./sound/ui/ui_click.mp3')" @change="onChangeLanguage" class="ss_select ss_marginright_sm">
        <option v-for="(language, code) in loc.languages" v-bind:value="code">
            {{ language }}
        </option>
    </select>

</script>

<script>
var comp_language_selector = {
    template: '#language-selector-template',
    props: ['languages', 'selectedLanguageCode', 'loc'],

    data: function () {
        return {
            languageCode: this.selectedLanguageCode,
        }
    },

    methods: {
        playSound (sound) {
            vueApp.playSound(sound);
        },

        onChangeLanguage: function () {
            vueApp.changeLanguage(this.languageCode);
            // Update localStorage for selected language.
            localStorage.setItem('selectedLanguage', this.languageCode);
            vueApp.playSound('./sound/ui/ui_onchange.mp3');
        }
    },

    watch: {
        selectedLanguageCode: function (code) {
            this.languageCode = code;
        }
    }
};
</script><script id="gdpr-template" type="text/x-template">
    <transition name="fade">
    <div v-show="isShowing">
        <div id="consent" v-show="showingNotification" class="gdpr_banner f_row">
            <div>{{ loc.gdpr_notification }} <a href="http://www.bluewizard.com/privacypolicy" target="_window">{{ loc.gdpr_link }}</a>
            </div>
            <div class="f_row">
                <button @click="onDisagreeClicked()" class="ss_button btn_red bevel_red ss_marginright ss_marginleft">{{ loc.gdpr_disagree }}</button>
                <button @click="onAgreeClicked()" class="ss_button btn_green bevel_green">{{ loc.gdpr_agree }}</button>
            </div>
        </div>

        <div id="doConsent" v-show="showingConsent" class="gdpr_banner f_row">
            <div>{{ loc.gdpr_consent }}</div>
            <div>
                <button @click="close()" class="ss_button btn_green bevel_green btn_md">{{ loc.ok }}</button>
            </div>
        </div>

        <div id="noConsent"v-show="showingNoConsent" class="gdpr_banner f_row">
            <div>{{ loc.gdpr_noConsent }}</div>
            <div>
                <button @click="close()" class="ss_button btn_green bevel_green btn_md">{{ loc.ok }}</button>
            </div>
        </div>
    </div>
    </transition>
</script>

<script>
var comp_gdpr = {
    template: '#gdpr-template',
    props: ['loc'],

    data: function () {
        return {
            isShowing: false,
            showingNotification: false,
            showingConsent: false,
            showingNoConsent: false
        }
    },

    methods: {
        show: function () {
            this.isShowing = true;
            this.showingNotification = true;
            this.showingConsent = false;
            this.showingNoConsent = false;
        },

        close: function () {
            this.isShowing = false;
            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        },

        onAgreeClicked: function () {
            this.showingConsent = true;
            this.showingNotification = false;
            extern.doConsent();
            vueApp.playSound('./sound/ui/ui_onchange.mp3');
        },

        onDisagreeClicked: function () {
            this.showingNoConsent = true;
            this.showingNotification = false;
            extern.doNotConsent();
            vueApp.playSound('./sound/ui/ui_onchange.mp3');
        }
    }
};
</script>
<script id="settings-template" type="text/x-template">
  <div>
    <h1 class="roundme_sm">{{ loc.p_settings_title }}</h1>

    <div id="popupInnards" class="roundme_sm fullwidth f_row f_spaced">
        <div id="account_left">
            <h3 class="nospace">{{ loc.p_settings_keybindings }}</h3>
            
            <div v-for="c in settingsUi.controls.game" class="nowrap">
                <settings-control-binder :loc="loc" :control-id="c.id" :control-value="c.value" @control-captured="onGameControlCaptured"></settings-control-binder>
                <div class="label">{{ loc[c.locKey] }}</div>
            </div>

            <div v-for="c in settingsUi.controls.spectate" class="nowrap">
                <settings-control-binder :loc="loc" :control-id="c.id" :control-value="c.value" @control-captured="onSpectateControlCaptured"></settings-control-binder>
                <div class="label">{{ loc[c.locKey] }}</div>
            </div>

            <h3 class="nospace ss_margintop">{{ loc.p_settings_language }}</h3>
            <language-selector :languages="languages" :loc="loc" :selectedLanguageCode="currentLanguageCode" class="ss_select"></language-selector>
        </div>
        
        <div id="settings_right">
            <div v-for="t in settingsUi.adjusters" class="nowrap">
                <settings-adjuster :loc="loc" :loc-key="t.locKey" :control-id="t.id" :control-value="t.value" :min="t.min" :max="t.max" :step="t.step" :multiplier="t.multiplier" @setting-adjusted="onSettingAdjusted"></settings-adjuster>
            </div>

            <div v-for="t in settingsUi.togglers" class="nowrap">
                <settings-toggler v-if="(t.id === 'shadowsEnabled' || t.id === 'highRes') ? showDetailSettings : true" :loc="loc" :loc-key="t.locKey" :control-id="t.id" :control-value="t.value" @setting-toggled="onSettingToggled"></settings-toggler>
            </div>

            <button v-show="showPrivacyOptions" @click="onPrivacyOptionsClicked" class="ss_button btn_blue bevel_blue btn_md ss_margintop_xl">{{ loc.p_settings_privacy }}</button>
        </div>
    </div>

    <div id="btn_horizontal" class="f_center">
        <button @click="onCloseClick()" class="ss_button btn_red bevel_red btn_sm">{{ loc.cancel }}</button>
        <button @click="onResetClick" class="ss_button btn_yolk bevel_yolk btn_sm">{{ loc.p_settings_reset }}</button>
        <button @click="onSaveClick()" class="ss_button btn_green bevel_green btn_sm">{{ loc.confirm }}</button>
    </div>

  </div>
</script>

<script id="settings-control-binder-template" type="text/x-template">
    <input ref="controlInput" @change="playSound('./sound/ui/ui_onchange.mp3')" type="text" v-model="currentValue" :placeholder="loc.press_key" class="ss_keybind clickme" :class="(currentValue === 'undefined' ? 'ss_keybind_undefined' : '')"
        v-on:mousedown="onMouseDown($event)"
        v-on:keydown="onKeyDown($event)" 
        v-on:keyup="onKeyUp($event)" 
        v-on:wheel="onWheel($event)"
        v-on:focusout="onFocusOut($event)">
</script>

<script>
var comp_settings_control_binder = {
    template: '#settings-control-binder-template',
    props: ['loc', 'controlId', 'controlValue'],
    
    data: function () {
        return {
            currentValue: this.controlValue,
            isCapturing: false
        }
    },

    methods: {
        playSound (sound) {
            vueApp.playSound(sound);
        },
        
        reset: function () {
            this.currentValue = this.controlValue;
            this.isCapturing = false;
            this.$refs.controlInput.blur();
        },

        capture: function (value) {
            this.isCapturing = false;
            this.$refs.controlInput.blur();
            this.$emit('control-captured', this.controlId, value);
        },

        onMouseDown: function (event) {
            if (!this.isCapturing) {
                this.currentValue = '';
                this.isCapturing = true;
            } else {
                this.playSound('./sound/ui/ui_onchange.mp3')
                this.capture('MOUSE ' + event.button);
            }
        },

        onKeyDown: function (event) {
            this.currentValue = '';
            event.stopPropagation();
        },

        onKeyUp: function (event) {
            event.stopPropagation();
            var key = event.key;

            if (key == 'Escape' || key == 'Tab' || key == 'Enter') {
                return;
            }

            if (key == ' ') {
                key = 'space';
                event.preventDefault();
            }
            
            this.capture(key);
        },

        onWheel: function (event) {
            if (this.isCapturing) {
                this.playSound('./sound/ui/ui_onchange.mp3')
                if (event.deltaY > 0) {
                    this.capture('WHEEL DOWN');
                } else if (event.deltaY < 0) {
                    this.capture('WHEEL UP');
                }
            }
        },

        onFocusOut: function (event) {
            this.reset();
        }
    },

    watch: {
        // The value prop gets updated by the parent control; watch for changes and update the backing field of the textbox
        controlValue: function (newValue) {
            this.currentValue = (newValue === null) ? 'undefined' : newValue;
        }
    }
};
</script><script id="settings-adjuster-template" type="text/x-template">
    <div>
        <h3 class="center_cont nospace">{{ loc[locKey] }}</h3>

        <div class="f_row ss_margintop">
            <input class="ss_slider" type="range" :min="min" :max="max" :step="step" v-model="currentValue" @change="onChange">
            <label class="ss_slider label">{{ Math.floor(currentValue * (multiplier || 1)) }}</label>
        </div>
    </div>
</script>

<script>
var comp_settings_adjuster = {
    template: '#settings-adjuster-template',
    props: ['loc', 'locKey', 'controlId', 'controlValue', 'min', 'max', 'step', 'multiplier'],

    data: function () {
        return {
            currentValue: this.controlValue
        }
    },

    methods: {
        onChange: function (event) {
            this.$emit('setting-adjusted', this.controlId, this.currentValue);
            vueApp.playSound('./sound/ui/ui_onchange.mp3');
        }
    },

    watch: {
        // controlValue prop could change when player X's out or clicks Cancel
        controlValue: function (newValue) {
            if (this.currentValue !== newValue) {
                this.currentValue = newValue;
            }
        }
    }
};
</script><script id="settings-toggler-template" type="text/x-template">
    <label class="ss_checkbox label"> {{ loc[locKey] }}
        <input type="checkbox" v-model="currentValue" @change="onChange($event)">
        <span class="checkmark"></span>
    </label>
</script>

<script>
var comp_settings_toggler = {
    template: '#settings-toggler-template',
    props: ['loc', 'locKey', 'controlId', 'controlValue'],

    data: function () {
        return {
            currentValue: this.controlValue
        }
    },

    methods: {
        onChange: function (event) {
            this.$emit('setting-toggled', this.controlId, this.currentValue);
            vueApp.playSound('./sound/ui/ui_onchange.mp3');
        }
    },

    watch: {
        // controlValue prop could change when player X's out or clicks Cancel
        controlValue: function (newValue) {
            if (this.currentValue !== newValue) {
                this.currentValue = newValue;
            }
        }
    }
};
</script>
<script>
var comp_settings = {
    template: '#settings-template',
    components: {
        'settings-control-binder': comp_settings_control_binder,
        'language-selector': comp_language_selector,
        'settings-adjuster': comp_settings_adjuster,
        'settings-toggler': comp_settings_toggler
    },
    props: ['loc', 'settingsUi', 'languages', 'currentLanguageCode', 'showPrivacyOptions'],

    data: function () {
        return {
            originalSettings: {},
            showDetailSettings: false,
            originalLanguage: '',
        }
    },
    
    methods: {
        captureOriginalSettings: function () {
            this.originalSettings = deepClone(vueData.settingsUi);
            this.originalLanguage = this.currentLanguageCode;
        },

        applyOriginalSettings: function () {
            vueData.settingsUi = this.originalSettings;
            this.showDetailSettings = !vueData.settingsUi.togglers.find( a => { return a.id === 'autoDetail'; }).value;

            console.log('applying original settings: ' + JSON.stringify(vueData.settingsUi));
        },

        onGameControlCaptured: function (id, value) {
            this.onControlCaptured(this.settingsUi.controls.game, id, value)
        },

        onSpectateControlCaptured: function (id, value) {
            this.onControlCaptured(this.settingsUi.controls.spectate, id, value)
        },

        onControlCaptured: function (controls, id, value) {
            value = value.toLocaleUpperCase();

            controls
                .forEach( (c) => {
                    if (c.id === id) {
                        c.value = value;
                    } else {
                        if (c.value === value) {
                            c.value = null;
                        }
                    }
            });
        },

        onSettingToggled: function (id, value) {
            console.log('value: ' + value);
            var toggler = this.settingsUi.togglers.find( (t) => { return t.id === id; });
            toggler.value = value;

            if (id === 'autoDetail') {
                this.showDetailSettings = !value;
            }
        },

        onSettingAdjusted: function (id, value) {
            this.settingsUi.adjusters.find( (a) => { return a.id === id; }).value = value;

            if (id === 'volume') {
                extern.setVolume(value);
            }

            if (id === 'mouseSpeed') {
                extern.setMouseSpeed(value);
            }
        },

        onVolumeChange: function () {
            extern.setVolume(this.settingsUi.volume);
        },

        onPrivacyOptionsClicked: function () {
            this.$emit('privacy-options-opened');
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },
        
        onCancelClick: function () {
            this.applyOriginalSettings();
            this.cancelLanguageSelect();
            this.$parent.close();
        },

        onCloseClick: function () {
            this.applyOriginalSettings();
            this.cancelLanguageSelect();
            this.$parent.close();
            vueApp.playSound('./sound/ui/ui_popupclose.mp3');
        },
        
        onSaveClick: function () {
            extern.applyUiSettings(this.settingsUi, this.originalSettings);
            this.resetOriginalLanguage();
            this.$parent.toggle();
            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        },

        onResetClick: function () {
            extern.resetSettings();
            vueApp.playSound('./sound/ui/ui_reset.mp3');
        },
        cancelLanguageSelect: function() {
            this.originalLanguage === vueApp.$data.currentLanguageCode ?
                vueApp.changeLanguage(vueApp.$data.currentLanguageCode) : vueApp.changeLanguage(this.originalLanguage);
            // Revert localStorage for language
            localStorage.setItem('selectedLanguage', this.originalLanguage);
            this.resetOriginalLanguage();
        },
        resetOriginalLanguage: function() {
            this.originalLanguage = '';
        },
        setSettings: function (settings) {
            var getSettingById = (list, id) => {
                    return list.filter( o => {
                            return o.id == id;
                    })[0];
            };

            getSettingById(this.settingsUi.controls.game, 'up').value = settings.controls.game.up;
            getSettingById(this.settingsUi.controls.game, 'down').value = settings.controls.game.down;
            getSettingById(this.settingsUi.controls.game, 'left').value = settings.controls.game.left;
            getSettingById(this.settingsUi.controls.game, 'right').value = settings.controls.game.right;
            getSettingById(this.settingsUi.controls.game, 'jump').value = settings.controls.game.jump;
            getSettingById(this.settingsUi.controls.game, 'fire').value = settings.controls.game.fire;
            getSettingById(this.settingsUi.controls.game, 'scope').value = settings.controls.game.scope;
            getSettingById(this.settingsUi.controls.game, 'reload').value = settings.controls.game.reload;
            getSettingById(this.settingsUi.controls.game, 'swap_weapon').value = settings.controls.game.swap_weapon;
            getSettingById(this.settingsUi.controls.game, 'grenade').value = settings.controls.game.grenade;
            getSettingById(this.settingsUi.controls.spectate, 'ascend').value = settings.controls.spectate.ascend;
            getSettingById(this.settingsUi.controls.spectate, 'descend').value = settings.controls.spectate.descend;
            
            getSettingById(this.settingsUi.adjusters, 'volume').value = settings.volume;
            getSettingById(this.settingsUi.adjusters, 'mouseSpeed').value = settings.mouseSpeed;

            getSettingById(this.settingsUi.togglers, 'mouseInvert').value = (settings.mouseInvert !== 1);
            getSettingById(this.settingsUi.togglers, 'holdToAim').value = settings.holdToAim;
            getSettingById(this.settingsUi.togglers, 'enableChat').value = settings.enableChat;
            getSettingById(this.settingsUi.togglers, 'autoDetail').value = settings.autoDetail;
            getSettingById(this.settingsUi.togglers, 'shadowsEnabled').value = settings.shadowsEnabled;
            getSettingById(this.settingsUi.togglers, 'highRes').value = settings.highRes;

            console.log('auto detail: ' + settings.autoDetail);
            this.showDetailSettings = !settings.autoDetail;
        },
    },

};
</script><script id="help-template" type="text/x-template">
    <div>
       <div id="horizontalTabs">
            <button id="faq_button" @click="toggleTabs" class="ss_bigtab bevel_blue ss_marginright" :class="(showTab1 ? 'selected' : '')">{{ loc.faq }}</button>
            <button id="fb_button" @click="toggleTabs" class="ss_bigtab bevel_blue" :class="(!showTab1 ? 'selected' : '')">{{ loc.feedback }}</button>
        </div>
        <div v-show="showTab1">
            
            <div id="feedback_panel">      

                <h1>{{ loc.faq_title }}</h1>

                <div v-for="qa in loc.faqItems">
                    <a :name="qa.anchor"></a>
                    <h3>{{ qa.q }}</h3>
                    <span v-html="qa.a"></span>
                </div>
                
                <hr>
                <div id="btn_horizontal" class="f_center">
                    <button @click="onBackClick" class="ss_button btn_md btn_red bevel_red ss_marginright">{{ loc.cancel }}</button>
                </div>
                
            </div>            
        </div>

        <div v-show="!showTab1">
            
            <div id="feedback_panel">
                <h1>{{ loc.fb_feedback_title }}</h1>
                
                <p>{{ loc.fb_feedback_intro }}</p>

                <div id="btn_horizontal" class="f_center">
                    <select v-model="selectedType" class="ss_field ss_marginright" @click="playSound('./sound/ui/ui_click.mp3')" @change="playSound('./sound/ui/ui_onchange.mp3')">
                        <option v-for="type in feedbackType" :value="type.id">{{ loc[type.locKey] }}</option>
                    </select>
                
                    <input id="feedbackEmail" v-model="email" :placeholder="loc.fb_email_ph" class="ss_field" v-on:keyup="validateEmail">
                </div>
                
                <div>
                    <textarea id="feedbackText" class="ss_field" v-model="feedback" :placeholder="loc.fb_feedback_ph" v-on:keyup="validateMessage"></textarea>
                </div>
                
                <div class="f_center f_col">
                    <span v-show="emailInvalid" class="ss_marginright error_text">{{ loc.fb_bad_email }}</span>
                    <span v-show="messageInvalid" class="ss_marginright error_text">{{ loc.fb_no_comment }}</span>
                </div>
                
                <div id="btn_horizontal" class="f_center">
                    <button @click="onBackClick" class="ss_button btn_md btn_red bevel_red ss_marginright">{{ loc.cancel }}</button>
                    <button @click="onSendClick" class="ss_button btn_md btn_green bevel_green">{{ loc.fb_send }}</button>
                </div>
            </div>

        </div>
    </div>
</script>

<script>
var comp_help = {
    template: '#help-template',
    props: ['loc'],
    data: function () {
        return {
            showTab1: true,
            feedbackType: [
                { id: 0, locKey: 'fb_type_commquest' },
                { id: 1, locKey: 'fb_type_request' },
                { id: 2, locKey: 'fb_type_bug' },
                { id: 3, locKey: 'fb_type_purchase' },
                { id: 4, locKey: 'fb_type_account' },
                { id: 5, locKey: 'fb_type_abuse' },
                { id: 6, locKey: 'fb_type_other' }
            ],
            selectedType: 0,
            email: '',
            feedback: '',
            doValidation: false,
            emailInvalid: false,
            messageInvalid: false,

        }
    },
    feedbackValidateTimeout: 0,
    methods: {
        playSound (sound) {
            vueApp.playSound(sound);
        },
        
        validateEmail: function () {
            if (!this.doValidation) {
                return;
            }
            // Insane e-mail-validating regex
            var re = /(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/;
            
            this.emailInvalid = (this.email === '' || !re.test(this.email));
            return !this.emailInvalid;
        },

        validateMessage: function () {
            if (!this.doValidation) {
                return;
            }
            this.messageInvalid = this.feedback === '';
            return !this.messageInvalid;
        },

        toggleTabs: function () {
            this.showTab1 = !this.showTab1;
            vueApp.playSound('./sound/ui/ui_toggletab.mp3');
        },
        
        onBackClick: function () {
            vueApp.$refs.helpPopup.toggle();
            vueApp.playSound('./sound/ui/ui_popupclose.mp3');
        },

        onSendClick: function () {
            this.doValidation = true;
            if (!this.validateEmail() || !this.validateMessage()) {
                return;
            }

            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');

            // Send that shit out
            extern.api_feedback(this.selectedType, this.email, this.feedback);
            this.$parent.toggle();

            this.selectedType = 0;
            this.feedback = null;
            this.email = null;
        }
    }
};
</script><script id="egg-store-template" type="text/x-template">
    <div class="fullwidth">
        
        <h1 class="roundme_sm">{{ loc.p_egg_shop_title }}</h1>

        <div class="f_row">

            <div id="popupInnards" class="box_blue4 roundme_md f_col center_cont ss_marginright_lg box_relative">
                
                <div id="eggshop_banner" class="hideme">
                    <img src="img/egg-shop-banner-left.png">
                    <div class="eggshop_banner_mid">
                        {{ loc.p_egg_shop_mostpopular }}
                    </div>
                </div>

                <p align="center" class="nospace"><img src="./img/eggshop_egg1.png" class="eggshop_image"></p>
                <h6 class="nospace shadow_bluebig4 eggshop_bigtitle">{{ loc.p_egg_shop_eggpile }}</h6>
                <span class="eggshop_subtitle text_white">{{ loc.p_egg_shop_eggpile_desc }}</span>
                <div class="eggshop_pricebox roundme_sm">$5 USD</div>
                <button class="ss_button btn_green bevel_green btn_sm center_h" @click="onItemClicked('egg_pack_small')">{{ loc.p_buy_item_confirm }}</button>
            </div>

            <div id="popupInnards" class="box_blue4 roundme_md f_col center_cont ss_marginright_lg box_relative">

                <div id="eggshop_banner">
                    <img src="img/egg-shop-banner-left.png">
                    <div class="eggshop_banner_mid">
                        {{ loc.p_egg_shop_mostpopular }}
                    </div>
                </div>

                <p align="center" class="nospace"><img src="./img/eggshop_egg2.png" class="eggshop_image"></p>
                <h6 class="nospace shadow_bluebig4 eggshop_bigtitle">{{ loc.p_egg_shop_eggbasket }}</h6>
                <span class="eggshop_subtitle text_white">{{ loc.p_egg_shop_eggbasket_desc }}</span>
                <div class="eggshop_pricebox roundme_sm">$10 USD</div>
                <button class="ss_button btn_green bevel_green btn_sm center_h" @click="onItemClicked('egg_pack_medium')">{{ loc.p_buy_item_confirm }}</button>
            </div>

            <div id="popupInnards" class="box_blue4 roundme_md f_col center_cont ss_marginright_lg box_relative">

                <div id="eggshop_banner" class="hideme">
                    <img src="img/egg-shop-banner-left.png">
                    <div class="eggshop_banner_mid">
                        {{ loc.p_egg_shop_mostpopular }}
                    </div>
                </div>

                <p align="center" class="nospace"><img src="./img/eggshop_egg3.png" class="eggshop_image"></p>
                <h6 class="nospace shadow_bluebig4 eggshop_bigtitle">{{ loc.p_egg_shop_eggbox }}</h6>
                <span class="eggshop_subtitle text_white">{{ loc.p_egg_shop_eggbox_desc }}</span>
                <div class="eggshop_pricebox roundme_sm">$20 USD</div>
                <button class="ss_button btn_green bevel_green btn_sm center_h" @click="onItemClicked('egg_pack_large')">{{ loc.p_buy_item_confirm }}</button>
            </div>

            <div id="popupInnards" class="box_blue4 roundme_md f_col center_cont box_relative">

                <div id="eggshop_banner">
                    <img src="img/egg-shop-banner-left.png">
                    <div class="eggshop_banner_mid">
                        {{ loc.p_egg_shop_bestvalue }}
                    </div>
                </div>

                <p align="center" class="nospace"><img src="./img/eggshop_egg4.png" class="eggshop_image"></p>
                <h6 class="nospace shadow_bluebig4 eggshop_bigtitle">{{ loc.p_egg_shop_eggcluckton }}</h6>
                <span class="eggshop_subtitle text_white">{{ loc.p_egg_shop_eggcluckton_desc }}</span>
                <div class="eggshop_pricebox roundme_sm">$50 USD</div>
                <button class="ss_button btn_green bevel_green btn_sm center_h" @click="onItemClicked('egg_pack_giant')">{{ loc.p_buy_item_confirm }}</button>
            </div>

        </div>

        <div id="popupInnards" class="box_blue4 roundme_md f_row center_cont ss_margintop box_relative eggshop_chicken_box" style="width: 80%; margin: 0 auto;">
            <h1 class="eggshop_megatitle shadow_bluebig4">Golden<br>Chicken!</h1>
        
            <img src="./img/ico_chicken.png" class="eggshop_chicken">

            <div class="eggshop_goldchicken_right">
                <ul>
                    <li> {{ loc.p_chicken_goldfeature1 }}</li>
                    <li> {{ loc.p_chicken_goldfeature2 }}</li>
                    <li v-html="loc.p_chicken_goldfeature3"></li>
                    <li> {{ loc.p_chicken_goldfeature4 }}</li>
                </ul>
                
                <div class="eggshop_pricebox roundme_sm">$9.99 USD</div>
                <button class="ss_button btn_green bevel_green width_md center_h" @click="onItemClicked('golden_chicken_pass')">{{ loc.p_chicken_goldbutton }}</button>
            </div>
        </div>
    </div>
</script>

<script>
var comp_egg_store = {
    template: '#egg-store-template',
    props: ['loc'],
    
    methods: {
        onItemClicked: function (sku) {
            this.$parent.hide();
            extern.buyProductForMoney(sku);
        }
    }
};
</script><script id="house-ad-big-template" type="text/x-template">
    <div v-show="(useAd !== null)">
        <button @click="onCloseClicked" class="popup_close splash_ad_close ad_close"></button>
        <img :src="adImageUrl" @click="onClicked" class="splash_ad_image centered roundme_md">
    </div>
</script>

<script>
var comp_house_ad_big = {
    template: '#house-ad-big-template',
    data: function() {
        return {
            removeOverlayClick: '',
        }
    },
    
    props: ['useAd'],

    bigAdTimeout: null,

    methods: {
        onCloseClicked: function () {
            console.log('big ad closed');
            this.close();
        },

        onClicked: function () {
            this.close();
            vueApp.playSound('./sound/ui/ui_click.mp3');
            extern.clickedHouseLink(this.useAd);
        },

        close: function () {
            vueApp.playSound('./sound/ui/ui_popupclose.mp3');
            this.$emit('big-house-ad-closed');
        },

        outsideClickClose: function() {
            const showingId = document.getElementById('house-ad-big-template', true);
            this.removeOverlayClick = this.handleOutsideClick;
            document.addEventListener('click', this.removeOverlayClick);
        },
        
        handleOutsideClick: function(e) {
            // Stop bubbling
            e.stopPropagation();
            // If the target does NOT include the class splash_ad_image use the onCloseClicked method and remove the eventListener
            if ( ! e.target.id.includes('splash_ad_image') ) {
                this.onCloseClicked();
                document.removeEventListener('click', this.removeOverlayClick);
            }
        },
    },

    computed: {
        adImageUrl: function () {
            if (!hasValue(this.useAd)) {
                return;
            }

            return 'img/promo/{0}{1}'.format(this.useAd.id, this.useAd.imageExt);
        }
    },

    watch: {
        useAd: function (bigAd) {
            if (hasValue(bigAd)) {
                this.$options.bigAdTimeout = setTimeout(function () {
                    vueApp.ui.houseAds.big = null;
                }, 15000);
                // Close with outside click
                this.outsideClickClose();
            }
        }
    }
};
</script><script id="house-ad-small-template" type="text/x-template">
    <img v-show="(useAd !== null)" :src="adImageUrl" @click="onClicked" class="news_banner roundme_md">
</script>

<script>
var comp_house_ad_small = {
    template: '#house-ad-small-template',
    
    props: ['useAd'],

    methods: {
        onClicked: function () {
            vueApp.playSound('./sound/ui/ui_click.mp3');
            extern.clickedHouseAdSmall(this.useAd);
        }
    },

    computed: {
        adImageUrl: function () {
            if (!hasValue(this.useAd)) {
                return;
            }

            return 'img/promo/{0}{1}'.format(this.useAd.id, this.useAd.imageExt);
        }
    }
};
</script><script id="item-template" type="text/x-template">
    <div class="store_item roundme_lg '.$is_hi.' '.$is_na.' clickme" ref="eggItemInvetory" :class="highlightSelected()" @click="onClick">
        <div v-if="showPrice" class="equip_smallprice">
            <svg class="equip_egg eggIcon"><use xlink:href="#icon-egg"></use></svg>
            <div class="equip_cost">{{ item.price }}</div>
        </div>
        <div v-if="showPhysicalMerch">
            <div class="equip_special">{{ loc.eq_special_merch }}</div>
        </div>
        <canvas ref="itemCanvas" class="equip_icon" width="250" height="250"></canvas>
    </div>
</script>

<script>
var comp_item = {
    template: '#item-template',
    props: ['loc', 'item', 'showItemOnly', 'isSelected'],

    data: function () {
        return {
            itemOnly: hasValue(this.showItemOnly) ? this.showItemOnly : false
        }
    },

    computed: {
        showPrice () {
            return this.isItemSellable() && this.item.price > 0;
        },

        showPhysicalMerch () {
            var physicalMerch = this.isItemSellable() && this.item.unlock === 'physical';
            return physicalMerch;
        },
    },

    mounted() {
        this.renderItem();
        this.itemHightlightedOrder();
    },
    methods: {
        isItemSellable: function () {
            return !this.itemOnly && vueData.equip.mode == vueData.equip.equipModes.shop;
        },

        renderItem: function () {
            extern.renderItemToCanvas(this.item, this.$refs.itemCanvas);
        },

        highlightSelected: function () {
            return this.isSelected ? 'highlight' : '';
        },

        onClick: function () {
            this.$emit('item-selected', this.item);
        },
        itemHightlightedOrder: function() {
            return this.$refs.eggItemInvetory.classList.contains('highlight') ? this.$refs.eggItemInvetory.style.order='-1' : null;
        },
    },

    watch: {
        item: function (val) {
            this.renderItem();
        }
    }
};
</script><script id="gold-chicken-template" type="text/x-template">
    <div>
    <div class="f_row fullwidth">

        <div id="popupInnards" class="box_blue3 roundme_sm f_col center_cont f_justify_start ss_marginright_lg">
            <h2 class="text_white shadow_blue4 nospace margintop_xl">{{ loc.p_chicken_goldchicken }}</h2>
            <p class="nospace"><strong>{{ loc.p_chicken_goldchicken_price }}</strong></p>
            <p align="center"><img src="./img/chicken_shadow.png" class="chicken_popup_image"></p>
            <div class="box_light roundme_sm fullwidth">
                <ul>
                    <li> {{ loc.p_chicken_goldfeature1 }} </li>
                    <li> {{ loc.p_chicken_goldfeature2 }} </li>
                    <li v-html="loc.p_chicken_goldfeature3"></li>
                    <li> {{ loc.p_chicken_goldfeature4 }} </li>
                </ul>
            </div>
            <button class="ss_button btn_green bevel_green btn_sm center_h" @click="onChickenClick">{{ loc.p_chicken_goldbutton }}</button>
        </div>
        
        <div id="popupInnards" class="box_blue3 roundme_sm f_col center_cont f_justify_start">
            <h2 class="text_white shadow_blue4 nospace margintop_xl">{{ loc.p_chicken_nugget }}</h2>
            <p class="nospace"><strong>{{ loc.p_chicken_nugget_price }}</strong></p>
            <p align="center"><img src="./img/nugget_shadow.png" class="chicken_popup_image"></p>
            <div class="box_light roundme_sm fullwidth">
                <ul>
                    <li>{{ loc.p_chicken_nuggetfeature1 }}</li>
                    <li> {{ loc.p_chicken_nuggetfeature2 }} </li>
                    <li v-html="loc.p_chicken_nuggetfeature3"></li>
                    <li> {{ loc.p_chicken_nuggetfeature4 }} </li>
                </ul>
            </div>
            
            <button class="ss_button btn_green bevel_green btn_sm center_h" @click="onNuggetClick">{{ loc.p_chicken_nuggetbutton }}</button>
        </div>
    </div>
    <div id="btn_horizontal" class="f_center">
        <button @click="onCloseClick()" class="ss_button btn_red bevel_red btn_sm">{{ loc.cancel }}</button>
    </div>
    </div>
</script>

<script>
var comp_gold_chicken_popup = {
    template: '#gold-chicken-template',
    props: ['loc'],
    methods: {
        onCloseClick: function () {
            this.$parent.close();
            vueApp.playSound('./sound/ui/ui_popupclose.mp3');
        },
        onChickenClick: function () {
            document.exitPointerLock();
            window.onkeydown = null;
            window.onkeyup = null;
            this.$parent.toggle();
            extern.buyGoldenChicken();
            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        },

        onNuggetClick: function () {
            this.$parent.hide();
            extern.startChickenNugget();
            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        }
    }
};
</script><script id="chicken-nugget-template" type="text/x-template">
    <div id="popupInnards" class="box_dark roundme_sm fullwidth f_col">
        
        <h3 class="nospace center_cont">{{ loc.p_nugget_instruction }}</h3>
        
        <iframe id="miniGameFrame" ref="miniGameFrame" src="about:blank" frameBorder="0" class="roundme_lg" ></iframe>
        
        <p align="center">
            <button id="gotNuggetOK" v-show="isMiniGameComplete" @click="onGotNugget" class="ss_button btn_shiny clickme invisible">{{ loc.p_nugget_button }}</button>
        </p>

        <div class="center_cont">
            <div id="chickenNuggetAdContainer" ref="chickenNuggetAdContainer" style="display: block; pointer-events: all;"></div>
        </div>
        
    </div>
</script>

<script>
var comp_chicken_nugget_popup = {
    template: '#chicken-nugget-template',
    props: ['loc'],

    data: function () {
        return {
            isMiniGameComplete: false
        }
    },

    methods: {
        placeBannerAdTag: function (tagEl) {
            this.$refs.chickenNuggetAdContainer.appendChild(tagEl);
        },
        
        loadMiniGame: function () {
            this.isMiniGameComplete = false;
            this.$refs.miniGameFrame.src = "app_nugget/index.html";

            // The ad tags are outside of the Vue app; manipulate the DOM directly
            this.$refs.chickenNuggetAdContainer.appendChild(vueApp.$options.multisizeAdTag);
            extern.showBannerAd(vueApp.$options.multisizeAdTag.id);
        },

        unloadMiniGame: function () {
            this.$refs.miniGameFrame.src = "about:blank";
        },

        onGotNugget: function () {
            this.$parent.hide();
            this.unloadMiniGame();
            extern.checkUpgrade();
        },

        onMiniGameCompleted: function () {
            this.isMiniGameComplete = true;
        }
    }
};
</script>
<script id="home-screen-template" type="text/x-template">
    <div>
        
        <house-ad-big id="big-house-ad" :useAd="ui.houseAds.big" @big-house-ad-closed="onBigHouseAdClosed"></house-ad-big>
        
        <div id="mainHead">
            <streamer-panel id="twitch_panel" :streams="twitchStreams" :title="loc.twitch_title" :viewers="loc.twitch_viewers" icon="ico_twitch"></streamer-panel>
            <!-- <streamer-panel id="youtube_panel" :streams="youtubeStreams" :title="loc.youtube_title" :viewers="loc.youtube_viewers" icon="ico_youtube"></streamer-panel> -->
        </div>

        <div id="mainLayout">
            <account-panel id="account_panel" ref="accountPanel" :loc="loc" :selected-language-code="currentLanguageCode" :eggs="eggs" :languages="languages" :show-corner-buttons="ui.showCornerButtons" :show-bottom="true" :photo-url="photoUrl" :is-anonymous="isAnonymous" :is-of-age="isOfAge" :show-targeted-ads="showTargetedAds" :ui="ui" @sign-in-clicked="onSignInClicked" @sign-out-clicked="onSignOutClicked"></account-panel>
            
            <div id="logo">
                <a href="https://www.shellshock.io" @click="playSound('./sound/ui/ui_click.mp3')"><img src="img/logo.png"></a>
            </div>

            <div id="panel_front_play">
                <play-panel id="play_game" ref="playPanel" :loc="loc" :player-name="playerName" :game-types="gameTypes" :current-game-type="currentGameType" :server-list="serverList" :current-server-id="currentServerId" :home="home" @playerNameChanged="onPlayerNameChanged"></play-panel>
                <stats-panel id="stats_panel" :loc="loc" :kills="kills" :deaths="deaths" :kdr="kdr" :streak="streak"></stats-panel>
            </div>
            
            <div id="panel_front_egg">
                <weapon-select-panel id="weapon_select" :current-class="classIdx"></weapon-select-panel>
                <button class="ss_button btn_md btn_yolk bevel_yolk" @click="onEquipClicked">{{ loc.eq_equipment }}</button>
            </div>

            <div id="panel_front_news">
                <div id="news_feed" class="front_panel roundme_md">
                    <div id="news_mask"></div>
                    <h3 class="nospace">{{ loc.home_latestnews }}</h3>
                    <newsfeed-panel id="news_scroll" ref="newsScroll" :current-language-code="currentLanguageCode"></newsfeed-panel>
                </div>
                <house-ad-small id="banner-ad" :useAd="ui.houseAds.small"></house-ad-small>
            </div>
        </div>

        <div id="mainFooter">
            <chicken-panel id="chicken_panel" :loc="loc" :is-upgraded="isUpgraded"></chicken-panel>
            <footer-links-panel id="footer_links_panel" :loc="loc"></footer-links-panel>
            <social-panel id="social_panel"></social-panel>
        </div>

        <!-- Popup: Firebase Sign In -->
        <large-popup id="firebaseSignInPopup" ref="firebaseSignInPopup" :overlay-close="false">
            <template slot="content">
                <h1 class="nospace">{{ loc.p_signin_head }}</h1>
                <div id="firebaseui-auth-container"></div>
                <div id="btn_horizontal" class="f_center">
                    <button @click="onSignInCancelClicked()" class="ss_button btn_red bevel_red btn_sm">{{ loc.cancel }}</button>
                </div>
            </template>
        </large-popup>

        <!-- Popup: Check Email -->
        <small-popup id="checkEmailPopup" ref="checkEmailPopup" :hide-cancel="true">
            <template slot="header">{{ loc.p_check_email_title }}</template>
            <template slot="content">
                <p>{{ loc.p_check_email_text1 }}:</p>
                <h5 class="nospace center_cont">{{ maskedEmail }}</h5>
                <p class="ss_marginbottom">{{ loc.p_check_email_text2 }}</p>
            </template>
            <template slot="confirm">{{ loc.ok }}</template>
        </small-popup>

        <!-- Popup: Resend Email -->
        <small-popup id="resendEmailPopup" ref="resendEmailPopup" @popup-confirm="onResendEmailClicked">
            <template slot="header">{{ loc.p_resend_email_title }}</template>
            <template slot="content">
                <p>{{ loc.p_resend_email_text1 }}:</p>
                <h5 class="nospace center_cont">{{ maskedEmail }}</h5>
                <p class="ss_marginbottom">{{ loc.p_resend_email_text2 }}</p>
            </template>
            <template slot="cancel">{{ loc.ok }}</template>
            <template slot="confirm">{{ loc.p_resend_email_resend }}</template>
        </small-popup>
        
    </div>
</script>

<script id="create-private-game-template" type="text/x-template">
    <div>
        <h1 class="roundme_sm">{{ loc.p_privatematch_title }}</h1>
    
        <div class="box_blue2 roundme_sm fullwidth">
            <div id="popupInnards" class="fullwidth f_row f_spaced">
                
                <div id="private_left" class="f_col f_start">
                    <h3 class="center_cont fullwidth">{{ loc.p_privatematch_gametype }}</h3>
                    <select name="gameType" v-model="pickedGameType" class="ss_select fullwidth" @click="playSound('./sound/ui/ui_click.mp3')" @change="playSound('./sound/ui/ui_onchange.mp3')">
                        <option v-for="g in gameTypes" v-bind:value="g.value">{{ loc[g.locKey] }}</option>
                    </select>
                    <button class="ss_button button_blue bevel_blue fullwidth" @click="onServerClick">{{ loc.server }}: {{ loc[serverLocKey] }}</button>
                    
                    <button name="play" @click="onPlayClick" class="ss_button btn_big fullwidth btn_green bevel_green btn_sm"><i class="fa fa-play fa-sm"></i> {{ loc.p_privatematch_create }}</button>
                    <!-- Player limit is not in place yet 
                        <h3 class="nospace">{{ loc.p_privatematch_players }}</h3>
                    
                    <div id="player_selector">
                        <img src="./img/ico_arrowLeft.png" class="numberArrow">
                        <input type="text" v-model class="ss_field fld_number">
                        <img src="./img/ico_arrowRight.png" class="numberArrow">
                    </div> -->
                </div>
                
                <div class="f_col j_start">
                    <h3 class="ss_marginleft_lg center_cont">{{ loc.p_privatematch_selectmap }}</h3>
                    
                    <div id="private_maps" class="ss_marginleft_lg roundme_md">
                        <img :src="mapImgPath" id="mapThumb" class="roundme_sm">
                        <div id="mapNav">
                            <button id="mapLeft" @click="onMapChange(-1)" class="clickme"> </button>
                            <h5 id="mapText">
                                {{ loc[mapLocKey].name }}
                                <span class="map_playercount shadow_grey roundme_sm">
                                    <img src="img/ico_eggColour_normal.png">
                                    <span class="ss_marginbottom_xs ss_marginright_xs">x</span>
                                    <span>{{loc[mapLocKey].suggested_player_limit}}</span>
                                </span>
                            </h5>
                            
                            <button id="mapRight" @click="onMapChange(1)" class="clickme"> </button>
                        </div>
                    </div>
                    
                </div>
            </div>
            
            <div id="btn_horizontal" class="f_center nospace">
                <button @click="onCloseClick()" class="ss_button btn_red bevel_red btn_sm">{{ loc.cancel }}</button>
            </div>
        </div>
    </div>
</script>

<script>
var comp_create_private_game_popup = {
    template: '#create-private-game-template',
    props: ['loc', 'serverLocKey', 'mapImgBasePath'],
    
    data: function () {
        return {
            showingServerList: false,
            pickedGameType: 0,
            gameTypes: vueData.gameTypes,
            mapIdx: 0,
            mapImgPath: this.mapImgBasePath + vueData.maps[0].img,
            mapLocKey: vueData.maps[0].locKey
        }
    },

    methods: {
        playSound (sound) {
            vueApp.playSound(sound);
        },
        
        onCloseClick: function () {
            this.$parent.close();
            vueApp.playSound('./sound/ui/ui_popupclose.mp3');
        },
        
        onServerClick: function () {
            this.showingServerList = true;
            this.$parent.toggle();
            vueApp.$refs.homeScreen.$refs.playPanel.$refs.pickServerPopup.toggle();
            vueApp.playSound('./sound/ui/ui_click.mp3');
        },

        onMapChange: function(dir) {
            this.mapIdx = ((this.mapIdx + dir) + vueData.maps.length) % vueData.maps.length;
            this.mapImgPath = this.mapImgBasePath + vueData.maps[this.mapIdx].img;
            this.mapLocKey = vueData.maps[this.mapIdx].locKey;

            console.log(this.mapIdx);

            vueApp.playSound('./sound/ui/ui_onchange.mp3');
        },

        onPlayClick: function () {
            this.$parent.toggle();
            
            extern.play({
                playType: vueData.playTypes.createPrivate,
                gameType: this.pickedGameType,
                mapIdx: this.mapIdx,
                playerName: vueData.playerName
            });

            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        }
    }
};
</script><script id="account-panel-template" type="text/x-template">
    <div>
        <div id="account_top">
            <input v-if="isAnonymous" type="image" src="img/attention_indicator.png" v-show="showCornerButtons" @click="onAnonWarningClick" class="account_icon roundme_sm attention_btn" v-bind:title="loc['account_title_shop']">
            <div class="account_eggs roundme_sm clickme" @click="onEggStoreClick" v-bind:title="loc['account_title_eggshop']">
                <img src="img/ico_goldenEgg.png" class="egg_icon">
                <span class="egg_count shadow_blue2_micro">{{ eggs }}</span>
            </div>
            <!-- <input type="image" src="img/ico_nav_leaderboards.png" class="account_icon roundme_sm"> -->
            <input type="image" src="img/ico_nav_shop.png" v-show="showCornerButtons" @click="itemStoreClick" class="account_icon roundme_sm" v-bind:title="loc['account_title_shop']">
            <input type="image" src="img/ico_nav_help.png" v-show="showCornerButtons" @click="onHelpClick" class="account_icon roundme_sm" v-bind:title="loc['account_title_faq']">
            <input type="image" src="img/ico_nav_share.png" v-show="showShareLinkButton" @click="onShareLinkClick" class="account_icon roundme_sm" v-bind:title="loc['account_title_invite']">
            <input type="image" src="img/ico_nav_settings.png" v-show="showCornerButtons" @click="onSettingsClick" class="account_icon roundme_sm" v-bind:title="loc['account_title_settings']">
            <input type="image" src="img/ico_nav_fullscreen.png" v-show="showCornerButtons" @click="onFullscreenClick" class="account_icon roundme_sm" v-bind:title="loc['account_title_fullscreen']">
        </div>
        
        <div id="account_bottom" v-show="showBottom">
            <language-selector :languages="languages" :loc="loc" :selectedLanguageCode="selectedLanguageCode"></language-selector>

            <button id="signInButton" v-show="(isAnonymous && showSignIn)" @click="onSignInClicked" class="ss_button btn_yolk bevel_yolk">{{ loc.sign_in }}</button>
            <button id="signOutButton" v-show="!isAnonymous" @click="onSignOutClicked" class="ss_button btn_yolk bevel_yolk">{{ loc.sign_out }}</button>
            <div id="player_photo" v-show="photoUrl !== null && photoUrl !== undefined && photoUrl !== '' && ! isAnonymous">
                <img :src="photoUrl" class="roundme_sm bevel_blue"/>
            </div>
        </div>
    </div>

</script>

<script>
var comp_account_panel = {
    template: '#account-panel-template',
    components: {
        'language-selector': comp_language_selector
    },
    props: ['loc', 'eggs', 'languages', 'selectedLanguageCode', 'showBottom', 'photoUrl', 'isAnonymous', 'isOfAge', 'showTargetedAds', 'showCornerButtons', 'ui'],
    
    data: function () {
        return {
            languageCode: this.selectedLanguageCode
        }
    },

    methods: {
        onEggStoreClick: function () {
            vueApp.showEggStorePopup();
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },
        itemStoreClick: function() {
            if (extern.inGame) {
                vueApp.$refs.gameScreen.hideGameMenu();
                extern.openEquipInGame();
                vueApp.switchToEquipUi();
            }
            else { 
                vueApp.switchToEquipUi();
            }
            vueApp.$refs.equipScreen.switchToShop();
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },
        onHelpClick: function () {
            vueApp.showHelpPopup();
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },

        onSettingsClick: function () {
            ga('send', 'event', 'open settings');
            vueApp.showSettingsPopup();
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },

        onFullscreenClick: function () {
            extern.toggleFullscreen();
            vueApp.playSound('./sound/ui/ui_click.mp3');
        },

        onSignInClicked: function () {
            vueApp.setDarkOverlay(true);
            this.$emit('sign-in-clicked');
            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        },

        onSignOutClicked: function () {
            vueApp.setDarkOverlay(true);
            this.$emit('sign-out-clicked');
            vueApp.playSound('./sound/ui/ui_reset.mp3');
        },

        onShareLinkClick: function () {
            extern.inviteFriends();
        },

        onAnonWarningClick: function() {
            vueApp.showAttentionPopup();
        }
    },

    computed: {
        showSignIn: function () {
            if (!isFromEU) {
                return true;
            }

            return isFromEU && this.isOfAge && this.showTargetedAds;
        },

        showShareLinkButton: function () {
            return this.showCornerButtons && (this.ui.showScreen === this.ui.screens.game);
        }
    }
};
</script>
<script id="streamer-panel-template" type="text/x-template">
    <div class="panel_streamer noscroll">
        <div id="stream_mask"></div>
        <h1 class="stream_head roundme_sm" :class="icon">{{ title }}</h1>
        <div id="stream_scroll" class="v_scroll" v-show="show">
            <div class="stream_item roundme_sm" v-for="s in streams">
                <a :href="s.link" target="_blank" @click="playSound('./sound/ui/ui_click.mp3')">
                    <img :src="s.image" class="stream_img roundme_sm"> {{ s.name }}
                    <p class="stream_viewers">{{ s.viewers }} {{ viewers }}</p>
                </a>
            </div>
        </div>
    </div>
</script>

<script>
var comp_streamer_panel = {
    template: '#streamer-panel-template',
    props: ['streams', 'title', 'viewers', 'icon'],
    methods: {
        playSound (sound) {
            vueApp.playSound(sound);
        }
    },
    computed: {
        show: function() {
            if (!this.streams) {
                return false;
            }

            return this.streams.length > 0;
        }
    }
};
</script><template id="stats_panel_template" type="text/x-template">
    <div class="front_panel roundme_md">
        <h3 class="nospace">{{ loc.home_stats }}</h3>
        <div id="stat_item" class="roundme_sm">
            <h4>{{ loc.kills.toUpperCase() }}</h4>
            <div class="stat_stat">{{ kills }}</div>
        </div>
        
        <div id="stat_item" class="roundme_sm">
            <h4>{{ loc.deaths.toUpperCase() }}</h4>
            <div class="stat_stat">{{ deaths }}</div>
        </div>
        
        <div id="stat_item" class="roundme_sm">
            <h4>{{ loc.kdr.toUpperCase() }}</h4>
            <div class="stat_stat">{{ kdr }}</div>
        </div>
        
        <div id="stat_item" class="roundme_sm">
            <h4>{{ loc.streak.toUpperCase() }}</h4>
            <div class="stat_stat">{{ streak }}</div>
        </div>
    </div>
</template>

<script>
var comp_stats_panel = {
    template: '#stats_panel_template',
    props: ['loc', 'kills', 'deaths', 'kdr', 'streak'],
};

</script>

<script id="play-panel-template" type="text/x-template">
    <div>
        <div class="front_panel roundme_md">

            <input name="name" :value="playerName" v-bind:placeholder="loc.play_enter_name" @change="onNameChange($event)" v-on:keyup="onPlayerNameKeyUp($event)" class="ss_field fullwidth"><br>
            <select name="gameType" v-model="pickedGameType" class="ss_select fullwidth" @change="onGameTypeChange($event)">
                <option v-for="g in gameTypes" v-bind:value="g.value">{{ loc[g.locKey] }}</option>
            </select><br>
            <button name="server" @click="onPickServerButtonClick" class="ss_button btn_blue bevel_blue fullwidth">{{ loc.server }}: {{ loc[serverLocKey] }}</button><br>
            <button name="play" @click="onPlayButtonClick" class="ss_button btn_big btn_green bevel_green fullwidth nospace"><i class="fa fa-play fa-sm"></i> {{ loc.home_play }}</button>
            
            <h3>{{ loc.home_privategames }}</h3>
            
            <div id="btn_horizontal" class="nospace">
                <button name="create" @click="onCreatePrivateGameClick" class="ss_button btn_sm btn_blue bevel_blue">{{ loc.home_create }}</button>&nbsp;
                <button name="join" @click="onJoinPrivateGameClick" class="ss_button btn_sm btn_blue bevel_blue">{{ loc.home_join }}</button>
            </div>
            
        </div>

        <!-- Popup: Pick Server -->
        <large-popup id="pickServerPopup" ref="pickServerPopup" @popup-closed="onPickServerPopupClosed">
            <template slot="header">{{ loc.server }}</template>
            <template slot="content">
                <server-list-popup id="server_list_popup" ref="serverListPopup" v-if="(serverList.length > 0)" :loc="loc" :servers="serverList" :picked-server-id="currentServerId" @server-picked="onServerPicked"></server-list-popup>
            </template>
        </large-popup>

        <!-- Popup: Create Private Game -->
        <large-popup id="createPrivateGamePopup" ref="createPrivateGamePopup">
            <template slot="content">
                <create-private-game-popup id="createPrivateGame" ref="createPrivateGame" :loc="loc" :server-loc-key="serverLocKey" map-img-base-path="./img/maps/"></create-private-game-popup>
            </template>
        </large-popup>

        <!-- Popup: Join Private Game -->
        <small-popup id="joinPrivateGamePopup" ref="joinPrivateGamePopup" :popup-model="home.joinPrivateGamePopup" @popup-confirm="onJoinConfirmed">
            <template slot="header">{{ loc.p_game_code_title }}</template>
            <template slot="content">
                <div class="error_text shadow_red" v-show="home.joinPrivateGamePopup.showInvalidCodeMsg">{{ loc.p_game_code_blank }}</div>
                <p><input type="text" class="ss_field ss_margintop ss_marginbottom fullwidth center_cont" v-model="home.joinPrivateGamePopup.code" v-bind:placeholder="loc.p_game_code_enter" v-on:keyup.enter="onJoinConfirmed"></p>
            </template>
            <template slot="cancel">{{ loc.cancel }}</template>
            <template slot="confirm">{{ loc.confirm }}</template>
        </small-popup>
    </div>
</script>

<script id="server-list-template" type="text/x-template">
    <div>
        <h1 class="roundme_sm">{{ loc.p_servers_title }}</h1>
        <div v-for="s in servers" :key="s.id">
            <div id="server_list_item">
                <input type="radio" :id="('rb_' + s.id)" name="pickServer" v-bind:value="s.id" v-model="serverId" @click="playSound('./sound/ui/ui_onchange.mp3')">
                <label :for="('rb_' + s.id)" class="serverName">{{ loc[s.locKey] }} </label>
                <label :for="('rb_' + s.id)" class="serverPingWrap roundme_sm">
                    <span class="pingBar" :class="barColorClass(s)" :style="barStyle(s)"></span>
                </label>
                <label :for="('rb_' + s.id)" class="serverPingNumber ss_marginleft_lg"> {{ s.ping }}ms</label>
            </div>
        </div>
        <div id="btn_horizontal" class="f_center">
            <button @click="onCancelClick()" class="ss_button btn_red bevel_red btn_sm">{{ loc.cancel }}</button>
            <button @click="onConfirmClick()" class="ss_button btn_green bevel_green btn_sm">{{ loc.ok }}</button>
        </div>
    </div>
</script>

<script>
var comp_server_list_popup = {
    template: '#server-list-template',
    props: ['loc', 'servers', 'pickedServerId'],

    data: function () {
        return {
            colorClasses: ['greenPing', 'yellowPing','orangePing', 'redPing'],
            serverId: this.pickedServerId
        }
    },

    methods: {
        playSound (sound) {
            vueApp.playSound(sound);
        },
        
        barColorClass: function (server) {
            var colorIdx = Math.min(3, Math.floor(server.ping / 100));
            return this.colorClasses[colorIdx];
        },

        barStyle: function (server) {
            return {
                width: Math.min(10, Math.max(0, server.ping / 100)) + 0.1 + 'em'
            }
        },

        onCancelClick: function () {
            this.serverId = this.pickedServerId;
            this.$parent.close();
            vueApp.playSound('./sound/ui/ui_popupclose.mp3');
        },

        onConfirmClick: function () {
            this.$emit('server-picked', this.serverId);
            this.$parent.close();
            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        }
    }
};
</script>
<script>
var comp_play_panel = {
    template: '#play-panel-template',
    components: {
        'create-private-game-popup': comp_create_private_game_popup,
        'server-list-popup': comp_server_list_popup
    },

    props: ['loc', 'playerName', 'gameTypes', 'currentGameType', 'serverList', 'currentServerId', 'home'],

    data: function() {
        return {
            pickedServerId: null,
            pickedGameType: this.currentGameType
        }
    },
            
    methods: {
        onPickServerButtonClick: function () {
            this.$refs.pickServerPopup.toggle();
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },
        
        onServerPicked: function (serverId) {
            if (vueData.currentServerId === serverId) { return; }
            
            vueData.currentServerId = serverId;
            extern.selectServer(vueData.currentServerId);
            vueApp.playSound('./sound/ui/ui_onchange.mp3');
        },

        onPickServerPopupClosed: function () {
            if (this.$refs.createPrivateGame.showingServerList) {
                this.$refs.createPrivateGame.showingServerList = false;
                this.$refs.createPrivateGamePopup.toggle();
            }
        },

        onNameChange: function (event) {
            console.log('name changed to: ' + event.target.value);
            this.$emit('playerNameChanged', event.target.value);
        },

        onPlayerNameKeyUp: function (event) {
            event.target.value = extern.fixStringWidth(event.target.value);

            // Send username to server to start the game!
            if (event.code == "Enter" || event.keyCode == 13) {
                if (vueData.playerName.length > 0) {
                    extern.play({
                        playType: vueData.playTypes.joinPublic,
                        playerName: vueData.playerName
                    });
                }
            }
        },

        onGameTypeChange: function (event) {
            extern.selectGameType(event.target.value);
            vueApp.playSound('./sound/ui/ui_onchange.mp3');
        },

        onPlayButtonClick: function () {
            if (!hasValue(this.playerName)) {
                console.log('invalid player name');
                vueApp.showGenericPopup('play_pu_name_title', 'play_pu_name_content', 'ok');
                return;
            }

            vueApp.game.respawnTime = 0;

            extern.play({
                playType: vueData.playTypes.joinPublic,
                gameType: this.pickedGameType,
                playerName: this.playerName,
                mapIdx: -1
            });
            
            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        },

        onCreatePrivateGameClick: function () {
            this.$refs.createPrivateGamePopup.toggle();
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },

        onJoinPrivateGameClick: function () {
            this.showJoinPrivateGamePopup(vueData.home.joinPrivateGamePopup.code);
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },

        showJoinPrivateGamePopup: function (showCode) {
            // The popup must be active before it will update; set code after showing
            this.$refs.joinPrivateGamePopup.show();
            vueData.home.joinPrivateGamePopup.code = showCode;
        },

        onJoinConfirmed: function () {
            vueData.home.joinPrivateGamePopup.code = vueData.home.joinPrivateGamePopup.code.replace(parsedUrl.root, '');
            this.$refs.joinPrivateGamePopup.hide();

            extern.play({
                playType: vueData.playTypes.joinPrivate,
                playerName: this.playerName,
                joinCode: vueData.home.joinPrivateGamePopup.code
            });
        }
    },

    computed: {
        serverLocKey: function () {
            if (!hasValue(this.serverList) || this.serverList.length === 0) {
                return '';
            }

            var server = this.serverList.find(s => {
                return s.id == vueData.currentServerId;
            });

            return hasValue(server) ? server.locKey : '';
        }
    },

    watch: {
        currentGameType: function (val) {
            this.pickedGameType = val;
        }
    }
};
</script><template id="weaponselect_panel_template" type="text/x-template">
    <div>
        <img src="img/ico_weapon_assaultRifle.png" class="weapon_img roundme_lg" :class="addSelectedCssClass(charClass.Soldier)" @click="selectClass(charClass.Soldier)">
        <img src="img/ico_weapon_shotgun.png" class="weapon_img roundme_lg" :class="addSelectedCssClass(charClass.Scrambler)" @click="selectClass(charClass.Scrambler)">
        <img src="img/ico_weapon_sniper.png" class="weapon_img roundme_lg" :class="addSelectedCssClass(charClass.Ranger)" @click="selectClass(charClass.Ranger)">
        <img src="img/ico_weapon_rocketLauncher.png" class="weapon_img roundme_lg" :class="addSelectedCssClass(charClass.Eggsploder)" @click="selectClass(charClass.Eggsploder)">
        <img src="img/ico_weapon_SMG.png" class="weapon_img roundme_lg" :class="addSelectedCssClass(charClass.Whipper)" @click="selectClass(charClass.Whipper)">
        <img src="img/ico_weapon_boltAction.png" class="weapon_img roundme_lg" :class="addSelectedCssClass(charClass.Crackshot)" @click="selectClass(charClass.Crackshot)">
    </div>
</template>

<script>
var comp_weapon_select_panel = {
    template: '#weaponselect_panel_template',
    props: ['currentClass'],

    data: function () {
        return {
            charClass: CharClass
        }
    },

    methods: {
        selectClass: function (classIdx) {
            extern.changeClass(classIdx);
            this.$emit('changed-class', classIdx);
            vueApp.playSound('./sound/ui/ui_click.mp3');
        },

        addSelectedCssClass: function (classIdx) {
            return (this.currentClass === classIdx)
                ? 'weapon_selected'
                : '';
        }
    }
};
</script>
<script id="newsfeed-panel-template" type="text/x-template">
    <div class="v_scroll">
        <div v-for="item in localizedItems" @click="onItemClicked(item)" class="news_item roundme_md" :class="applyClickClass(item)">
            <img :src="('img/newsItems/' + item.image)" class="news_img roundme_sm">
            <p>{{ item.msg }}</p>
        </div>
    </div>
</script>

<script>
var comp_newsfeed_panel = {
    template: '#newsfeed-panel-template',
    props: ['currentLanguageCode'],

    data: function () {
        return {
            items: [],
            localizedItems: []
        }
    },

    mounted: function () {
        var outer = this;

        fetch('newsItems.json')
            .then(function(response) {
                response.json()
                    .then(function(parsedItemList) {
                        outer.items = parsedItemList;
                        outer.localizeItems();
                    });
            });
    },

    methods: {
        localizeItems: function () {
            let locItemList = [];
            const lang = 'en';
            this.items.forEach( (item) => {
                var locEntry = item.loc.find((l) => {
                    // Since we have no localization for news items only display en
                    // return l.code === this.currentLanguageCode;
                    return l.code === lang;
                });
                
                item.msg = hasValue(locEntry) ? locEntry.msg : '';

                locItemList.push(item);
            });

            this.localizedItems = locItemList;
        },

        onItemClicked: function(item) {
            extern.clickedHouseLink(item);
            vueApp.playSound('./sound/ui/ui_click.mp3');
        },

        applyClickClass: function (item) {
            return extern.hasHouseLink(item) ? 'clickme' : '';
        }
    },

    watch: {
        // Rebuild the localized item array when the current language code changes
        currentLanguageCode: function (newCode) {
            this.localizeItems();
        }
    }
};
</script><script id="chicken-panel-template" type="text/x-template">
    <div id="showBuyPassDialogButton">
        <img src="img/ico_chickenBadge.png" v-show="isUpgraded">
        <div v-show="!isUpgraded">
            <img src="img/anim_chicken.gif" @click="onChickenClick" class="clickme">
        
            <div id="buyPassChickenSpeech">
                <img src="img/speechtail.png" class="buyPassChickenSpeechTail">
                <span v-html="loc.chicken_cta"></span>
            </div>
        </div>
    </div>
</script>

<script>
var comp_chicken_panel = {
    template: '#chicken-panel-template',
    props: ['loc', 'isUpgraded'],

    methods: {
        onChickenClick: function () {
            vueApp.playSound('./sound/ui/ui_chicken.mp3');
            vueApp.showGoldChickenPopup();
        }
    }
};
</script><script id="footer-links-panel-template" type="text/x-template">
    <div class="center_h">
    <a @click="onChangelogClicked" class="clickme">{{ version }}</a> | 
    <a href="https://shell-shockers.myshopify.com/collections/all" target="_blank" @click="playSound('./sound/ui/ui_click.mp3')">{{ loc.footer_merchandise }}</a> | 
    <a href="https://www.bluewizard.com/privacypolicy" target="_blank" @click="playSound('./sound/ui/ui_click.mp3')">{{ loc.footer_privacypolicy }}</a> | 
    <a href="https://bluewizard.com/terms/" target="_blank" @click="playSound('./sound/ui/ui_click.mp3')">{{ loc.footer_termsofservice }}</a> | 
    <a href="https://www.bluewizard.com" target="_blank" @click="playSound('./sound/ui/ui_click.mp3')">&copy; 2019 {{ loc.footer_bluewizard }}</a>
    </div>
</script>

<script>
var comp_footer_links_panel = {
    template: '#footer-links-panel-template',
    props: ['loc'],

    data: function () {
        return {
            version: version
        }
    },

    methods: {
        onChangelogClicked: function () {
            vueApp.showChangelogPopup();
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },
        playSound (sound) {
            vueApp.playSound(sound);
        }
    }
};
</script>
<script id="social-panel-template" type="text/x-template">
    <div class="social_icons roundme_sm">
        <a href="http://eepurl.com/dFPPwb" target="_blank"><img src="img/ico_social_newsletter.png" class="social_icon" @click="playSound('./sound/ui/ui_click.mp3')"></a>
        <a href="https://discord.gg/bluewizard" target="_blank"><img src="img/ico_social_discord.png" class="social_icon" @click="playSound('./sound/ui/ui_click.mp3')"></a>
        <a href="https://www.facebook.com/ShellShockersGame" target="_blank"><img src="img/ico_social_facebook.png" class="social_icon" @click="playSound('./sound/ui/ui_click.mp3')"></a>
        <a href="https://twitter.com/eggcombat" target="_blank"><img src="img/ico_social_twitter.png" class="social_icon" @click="playSound('./sound/ui/ui_click.mp3')"></a>
    </div>
</script>

<script>
var comp_social_panel = {
    template: '#social-panel-template',
    methods: {
        playSound (sound) {
            vueApp.playSound(sound);
        }
    }
};
</script>
<script>
var comp_home_screen = {
    template: '#home-screen-template',
    components: {
        'streamer-panel': comp_streamer_panel,
        'stats-panel': comp_stats_panel,
        'play-panel': comp_play_panel,
        'weapon-select-panel': comp_weapon_select_panel,
        'newsfeed-panel': comp_newsfeed_panel,
        'house-ad-big': comp_house_ad_big,
        'house-ad-small': comp_house_ad_small,
        'account-panel': comp_account_panel,
        'chicken-panel': comp_chicken_panel,
        'footer-links-panel': comp_footer_links_panel,
        'social-panel': comp_social_panel
    },

    data: function () {
        return vueData;
    },

    methods: {
        playSound (sound) {
            vueApp.playSound(sound);
        },

        onEquipClicked: function () {
            vueApp.switchToEquipUi();
            vueApp.playSound('./sound/ui/ui_equip.mp3');
        },

        showSignIn: function () {
            this.$refs.firebaseSignInPopup.toggle();
            extern.showSignInDialog();
        },

        onSignInClicked: function () {
            this.showSignIn();
        },

        onSignInCancelClicked: function () {
            this.$refs.firebaseSignInPopup.hide();
            vueApp.playSound('./sound/ui/ui_popupclose.mp3');
        },

        onSignOutClicked: function () {
            extern.signOut();
        },

        onResendEmailClicked: function () {
            extern.sendFirebaseVerificationEmail();

            vueApp.showGenericPopup('verify_email_sent', 'verify_email_instr', 'ok');
        },

        onBigHouseAdClosed: function () {
            console.log('big house ad closed event received');
            this.ui.houseAds.big = null;
        },

        onPlayerNameChanged: function (newName) {
            console.log('play name event handler');
            vueApp.setPlayerName(newName);
            vueApp.playSound('./sound/ui/ui_onchange.mp3');
        }
    }
};
</script><script id="equip-screen-template" type="text/x-template">
    <div>
        <div id="equip_wrapper">

            <account-panel id="account_panel" ref="accountPanel" :loc="loc" :eggs="eggs" :show-corner-buttons="ui.showCornerButtons" :ui="ui" :show-bottom="false" :is-anonymous="isAnonymous"></account-panel>

            <div id="equip_box">

                <section id="equip_panel_left" class="equip_panel left_panel">
                    <div class="equip_panelhead">
                    </div>
                    <div id="equip_sidebox" class="roundme_md">
                        <equipped-slots id="equip.equipped_slots" ref="equip.equipped_slots" :loc="loc" :primary-item="equip.equippedPrimary" :secondary-item="equip.equippedSecondary" :hat-item="equip.equippedHat" :stamp-item="equip.equippedStamp" @equipped-type-selected="onEquippedTypeSelected"></equipped-slots>
                        <color-select id="equip.equipped_slots" ref="colorSelect" :loc="loc" :color-idx="equip.colorIdx" :extra-colors-locked="equip.extraColorsLocked" @color-changed="onColorChanged"></color-select>
                    </div>
                    <p align="center"><button @click="onRedeemClick" class="ss_button btn_blue1 btn_md bevel_blue">{{ loc.eq_redeem }}</button></p>
                </section>
                <!-- end.left_panel -->

                <section id="equip_panel_middle" class="equip_panel middle_panel">
                    <div class="equip_panelhead panel_tabs">
                        <button class="ss_bigtab bevel_blue ss_marginright" :class="getButtonToggleClass(equip.equipModes.inventory)" @click="switchToInventory">{{ loc.eq_inventory }}</button>
                        <button class="ss_bigtab bevel_blue" :class="getButtonToggleClass(equip.equipModes.shop)" @click="switchToShop">{{ loc.eq_shop }}</i></button>
                    </div>

                    <div id="equip_purchase_top" class="equip_purchase_top">
                        <!-- <div></div> -->
                        <price-tag id="price_tag" class="ss_marginright" v-if="equip.buyingItem" ref="price_tag" :loc="loc" :item="equip.buyingItem" @buy-item-clicked="onBuyItemClicked"></price-tag>
                        <physical-tag id="physical-tag" class="ss_marginright" v-if="equip.physicalUnlockPopup.item" ref="physical-tag" :loc="loc" :item="equip.physicalUnlockPopup.item" @buy-item-clicked="onBuyItemClicked"></physical-tag>
                        <!-- <p v-if="equip.buyingItem">{{ equip.buyingItem }}</p>
                        <p v-if="equip.physicalUnlockPopup">{{ equip.physicalUnlockPopup.item }}</p> -->
                        
                        <!--<item-timer id="item_timer" ref="item_timer" :loc="loc"></item-timer>-->
                    </div>

                    <div id="equip_weapon_panel">
                        <weapon-select-panel id="weapon_select" :current-class="classIdx" @changed-class="onChangedClass"></weapon-select-panel>
                        <button class="ss_button btn_md btn_red bevel_red" @click="onBackClick"><i class="fas fa-backward"></i> {{ loc.back }}</button>
                    </div>
                </section>
                <!-- end .middle_panel -->

                <section id="equip_panel_right" class="equip_panel right_panel">
                    <item-type-selector id="item_type_selector" ref="item_type_selector" :selected-item-type="equip.selectedItemType" :show-special-items="equip.showSpecialItems" :in-shop="isInShop" @item-type-changed="onItemTypeChanged" @tagged-items-clicked="onTaggedItemsClicked"></item-type-selector>

                    <div id="equip_sidebox" class="roundme_md">
                        <item-grid id="item_grid" ref="item_grid" :loc="loc" :grid-class="getGridClass" :items="equip.showingItems" :selectedItem="equip.selectedItem" :category-loc-key="equip.categoryLocKey" :in-shop="isInShop" @item-selected="onItemSelected" @switch-to-shop="onSwitchToShopClicked"></item-grid>
                        <!--<house-ad-small id="banner-ad" v-show="!isInShop"></house-ad-small>-->
                    </div>
                </section>
                <!-- .right_panel-->

            </div>
        </div>

        <!-- Popup: Buy Item -->
        <small-popup id="buyItemPopup" ref="buyItemPopup" @popup-confirm="onBuyItemConfirm">
            <template slot="header">{{ loc.p_buy_item_title }}</template>
            <template slot="content">
                <div>
                    <canvas id="buyItemCanvas" ref="buyItemCanvas" width="250" height="250"></canvas>
                </div>
                <div class="f_row f_center">
                    <img src="img/ico_goldenEgg.png" class="egg_icon"/>
                    <h1>{{ (equip.buyingItem) ? equip.buyingItem.price : '' }}</h1>
                </div>
            </template>
            <template slot="cancel">{{ loc.p_buy_item_cancel }}</template>
            <template slot="confirm">{{ loc.p_buy_item_confirm }}</template>
        </small-popup>

        <!-- Popup: Redeem Code -->
        <small-popup id="redeemCodePopup" ref="redeemCodePopup" :popup-model="equip.redeemCodePopup" @popup-confirm="onRedeemCodeConfirm">
            <template slot="header">{{ loc.p_redeem_code_title }}</template>
            <template slot="content">
                <div class="error_text shadow_red" v-show="equip.redeemCodePopup.showInvalidCodeMsg">{{ loc.p_redeem_code_no_code }}</div>
                <p><input type="text" class="ss_field ss_margintop ss_marginbottom center_cont width_lg" v-model="equip.redeemCodePopup.code" v-bind:placeholder="loc.p_redeem_code_enter"></p>
            </template>
            <template slot="cancel">{{ loc.cancel }}</template>
            <template slot="confirm">{{ loc.confirm }}</template>
        </small-popup>

        <!-- Popup: Physical Unlock -->
        <small-popup id="physicalUnlockPopup" ref="physicalUnlockPopup" :popup-model="equip.physicalUnlockPopup" @popup-confirm="onPhysicalUnlockConfirm">
            <template slot="header">{{ loc.p_physical_unlock_title }}</template>
            <template slot="content">
                <div v-if="(equip.physicalUnlockPopup.item !== null)">
                    <div>
                        <item :item="equip.physicalUnlockPopup.item" :isSelected="false" :show-item-only="true"></item>
                        <div class="f_row f_center">
                            <img src="img/ico_goldenEgg.png" class="egg_icon"/>
                            <h1>{{ loc.p_buy_special_price }}</h1>
                        </div>
                    </div>
                    <div class="popup_sm__item_desc">
                        {{ loc[equip.physicalUnlockPopup.item.item_data.physicalUnlockLocKey] }}
                    </div>
                </div>
            </template>
            <template slot="cancel">{{ loc.cancel }}</template>
            <template slot="confirm">{{ loc.confirm }}</template>
        </small-popup>

    </div>
</script>

<script id="equipped-slots-template" type="text/x-template">
    <div>
        <h3 class="margins_sm">{{ loc.eq_equipped }}</h3>
        <div id="equip_equippedslots">
            <div class="equip_item roundme_lg clickme f_row f_center" @click="onClick(itemType.Primary)">
                <item id="primary_item" ref="primary_item" v-if="primaryItem" :item="primaryItem" class="equip_icon"></item>
            </div>

            <div class="equip_item roundme_lg clickme f_row f_center" @click="onClick(itemType.Secondary)">
                <item id="secondary_item" ref="secondary_item" v-if="primaryItem" :item="secondaryItem" class="equip_icon"></item>
            </div>
            
            <div class="equip_item roundme_lg clickme f_row f_center" @click="onClick(itemType.Hat)">
                <item id="hat_item" ref="hat_item" v-if="hatItem" :item="hatItem"></item>
                <div v-if="!hatItem" class="equip_icon equip_icon_hat"></div>
            </div>
            
            <div class="equip_item roundme_lg clickme f_row f_center" @click="onClick(itemType.Stamp)">
                <item id="stamp_item" ref="stamp_item" v-if="stampItem" :item="stampItem"></item>
                <div v-if="!stampItem" class="equip_icon equip_icon_stamp"></div>
            </div>
        </div>
    </div>
</script>

<script>
var comp_equipped_slots = {
    template: '#equipped-slots-template',
    components: { 'item': comp_item },
    props: ['loc', 'primaryItem', 'secondaryItem', 'hatItem', 'stampItem'],

    data: function () {
        return {
            itemType: ItemType
        }
    },

    methods: {
        onClick: function (itemType) {
            this.$emit('equipped-type-selected', itemType);
        }
    },

    computed: {
        emptyHatClass: function () {
            return (this.hatItem === null) ? 'equip_icon_hat' : '';
        },

        emptyStampClass: function () {
            return (this.stampItem === null) ? 'equip_icon_stamp' : '';
        }
    }
};
</script><script id="color-select-template" type="text/x-template">
    <div>    
        <h3 class="margins_sm">{{ loc.eq_color }}</h3>
        <div id="equip_free_colors" class="center_cont">
            <svg v-for="(c, index) in freeColors" class="eggIcon equip_color" :style="{ color: c }" :class="isSelectedClass(index)" @click="onClick(index)"><use xlink:href="#icon-egg"></use></svg>
        </div>
        <div id="equip_paid_colors" class="center_cont ss_marginbottom_lg">
            <svg v-for="(c, index) in paidColors" class="eggIcon equip_color" :style="{ color: c }" :class="isSelectedClass(index + freeColors.length)" @click="onClick(index + freeColors.length)"><use :xlink:href="getExtraColorEggIcon(index + freeColors.length)"></use></svg>
        </div>
    </div>
</script>

<script>
var comp_color_select = {
    template: '#color-select-template',
    props: ['loc', 'colorIdx', 'extraColorsLocked'],
    
    data: function () {
        return {
            freeColors: freeColors,
            paidColors: paidColors
        }
    },

    methods: {
        isSelectedClass: function (idx) {
            return (idx === this.colorIdx) ? 'selected' : ''
        },

        getExtraColorEggIcon: function (idx) {
            return (this.extraColorsLocked === true) ? '#icon-egg-locked' : '#icon-egg';
        },

        onClick: function (idx) {
            if (idx >= freeColors.length && this.extraColorsLocked === true) {
                vueApp.showGoldChickenPopup();
                vueApp.playSound('./sound/ui/ui_chicken.mp3');
                return;
            }

            this.$emit('color-changed', idx);
        }
    }
};
</script><script id="item-timer-template" type="text/x-template">
    <div>
        <div id="equip_timerem" class="box_blue3 roundme_sm shadow_blue4">
            <i class="fas fa-hourglass-start"></i> 9{{ loc.eq_day }}<span class="blink">:</span>12{{ loc.eq_hour }}
            <br>{{ loc.eq_remaining }}
        </div>
    </div>
</script>

<script>
var comp_item_timer = {
    template: '#item-timer-template',
    props: ['loc']
};
</script><script id="price-tag-template" type="text/x-template">
    <div id="equip_purchase_items" class="equip_purchase_items">
        <div id="equip_pricetag" class="equip_pricetag shadow_blue2">
            <img src="img/pricetag_left.png" class="equip_pricetag__endpiece">
            <div class="equip_pricetag__tag equip_pricetag__is_buy_tag">
                <img src="img/ico_goldenEgg.png">{{ item.price }}
            </div>
            <img src="img/pricetag_right.png" class="equip_pricetag__endpiece">
        </div>
        <button class="ss_button btn_yolk bevel_yolk is_purchase_btn" @click="onBuyClick">{{ loc.eq_buy }}</button>
    </div>
</script>

<script>
var comp_price_tag = {
    template: '#price-tag-template',
    props: ['loc', 'item'],

    methods: {
        onBuyClick: function () {
            this.$emit('buy-item-clicked', this.item);
        }
    }
};
</script><script id="physical-tag-template" type="text/x-template">
    <div id="equip_get_physical_item" class="equip_purchase_items">
        <div id="equip_pricetag" class="equip_pricetag shadow_blue2">
            <img src="img/pricetag_left.png">
            <div class="equip_pricetag__tag equip_pricetag__is_special_tag">
                <img src="img/ico_goldenEgg.png" class="ss_marginright">{{ loc.p_buy_special_price }}
            </div>
            <img src="img/pricetag_right.png">
        </div>
        <button class="ss_button btn_yolk bevel_yolk is_special_get_btn" @click="onBuyClick">{{ loc.p_chicken_goldbutton }}</button>
    </div>
</script>

<script>
var comp_physical_tag = {
    template: '#physical-tag-template',
    props: ['loc', 'item'],

    methods: {
        onBuyClick: function () {
            this.$emit('buy-item-clicked', this.item);
        }
    }
};
</script><script id="item-type-selector-template" type="text/x-template">
    <div>
        <div id="equip_itemtype" class="equip_panelhead">
            <img src="img/ico_weaponPrimary.png" class="ico_itemtype clickme roundme_lg" :class="getSelectedClass(itemType.Primary)" @click="onItemTypeClick(itemType.Primary)">
            <img src="img/ico_weaponSecondary.png" class="ico_itemtype clickme roundme_lg" :class="getSelectedClass(itemType.Secondary)" @click="onItemTypeClick(itemType.Secondary)">
            <img src="img/ico_hat.png" class="ico_itemtype clickme roundme_lg" :class="getSelectedClass(itemType.Hat)" @click="onItemTypeClick(itemType.Hat)">
            <img src="img/ico_stamp.png" class="ico_itemtype clickme roundme_lg" :class="getSelectedClass(itemType.Stamp)" @click="onItemTypeClick(itemType.Stamp)">
            <img src="img/ico_specialItem.png" v-show="inShop && showSpecialItems" class="ico_itemtype clickme roundme_lg" :class="getSelectedClass('tagged')" @click="onTaggedTypeClick">
        </div>
    </div>
</script>

<script>
var comp_item_type_selector = {
    template: '#item-type-selector-template',
    props: ['showSpecialItems', 'selectedItemType', 'inShop'],

    data: function () {
        return {
            itemType: ItemType,
            showingTagged: false
        }
    },

    methods: {
        onItemTypeClick: function (itemType) {
            this.$emit('item-type-changed', itemType);
        },

        onTaggedTypeClick: function () {
            this.$emit('tagged-items-clicked');
        },

        getSelectedClass: function (itemType) {
            return (itemType === this.selectedItemType)
                ? 'selected'
                : '';
        }
    }
};
</script><script id="item-grid-template" type="text/x-template">
    <div>
        <div id="item_mask"></div>
        <h3 class="margins_sm">{{ loc[categoryLocKey] }}</h3>
        <div id="equip_grid" :class="gridClass">
            <item v-for="i in items" :loc="loc" :item="i" :key="i.id" :isSelected="isSelected(i)" @item-selected="onItemSelected"></item>
            <div v-show="!inShop" class="store_item roundme_lg '.$is_hi.' '.$is_na.' clickme morestuff bevel_green" @click="onSwitchToShopClick"></div>
            <div v-show="inShop && (items.length === 0)" class="store_item roundme_lg '.$is_hi.' '.$is_na.' soldout">
                <div class="soldout_head shadow_bluebig5" v-html="loc.eq_sold_out_head"></div>
                <div class="soldout_text" v-html="loc.eq_sold_out_text"></div>
            </div>
        </div>
    </div>
</script>

<script>
var comp_item_grid = {
    template: '#item-grid-template',
    components: { 'item': comp_item },
    props: ['loc', 'items', 'selectedItem', 'gridClass', 'categoryLocKey', 'inShop'],

    methods: {
        onItemSelected: function (selectedItem) {
            this.$emit('item-selected', selectedItem);
        },

        isSelected: function (item) {
            if (!hasValue(this.selectedItem)) {
                return false;
            }

            return (this.selectedItem.id === item.id);
        },

        onSwitchToShopClick: function () {
            this.$emit('switch-to-shop');
            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        }
    },

    computed: {
        categoryName: function () {
            if (!hasValue(this.selectedItem)) {
                return null;
            }

            return this.loc['item_type_' + this.selectedItem.item_type_id];
        }
    }
};
</script>
<script>
var comp_equip_screen = {
    template: '#equip-screen-template',
    components: {
        'account-panel': comp_account_panel,
        'equipped-slots': comp_equipped_slots,
        'color-select': comp_color_select,
        'item-timer': comp_item_timer,
        'price-tag': comp_price_tag,
        'physical-tag': comp_physical_tag,
        'item-type-selector': comp_item_type_selector,
        'item-grid': comp_item_grid,
        'house-ad-small': comp_house_ad_small,
        'weapon-select-panel': comp_weapon_select_panel,
        'item': comp_item,
        // 'account-panel': comp_account_panel,
        'house-ad-small': comp_house_ad_small
    },

    data: function () {
        return vueData;
    },

    equippedItems: {},

    methods: {
        setup: function (itemType) {
            if (!itemType) { itemType = ItemType.Primary; }
            this.updateEquippedItems();
            this.poseEquippedItems();
            if (itemType === 'tagged') {
                this.populateItemGridWithTagged(this.equip.specialItemsTag);
            } else {
                this.populateItemGridWithType(itemType);
            }
            this.selectEquippedItemForType();
        },

        updateEquippedItems: function () {
            this.$options.equippedItems = extern.getEquippedItems();

            this.equip.equippedHat = this.$options.equippedItems[ItemType.Hat];
            this.equip.equippedStamp = this.$options.equippedItems[ItemType.Stamp];
            this.equip.equippedPrimary = this.$options.equippedItems[ItemType.Primary];
            this.equip.equippedSecondary = this.$options.equippedItems[ItemType.Secondary];
        },

        poseEquippedItems: function () {
            this.posingHat = this.equip.equippedHat;
            this.posingStamp = this.equip.equippedStamp;
            this.posingWeapon = (this.equip.showingWeaponType === ItemType.Primary)
                ? this.equip.equippedPrimary
                : this.equip.equippedSecondary;

            this.workItBaby();
        },

        selectEquippedItemForType: function () {
            switch (this.equip.selectedItemType) {
                case ItemType.Hat: this.equip.selectedItem = this.equip.equippedHat; break;
                case ItemType.Stamp: this.equip.selectedItem = this.equip.equippedStamp; break;
                case ItemType.Primary: this.equip.selectedItem = this.equip.equippedPrimary; break;
                case ItemType.Secondary: this.equip.selectedItem = this.equip.equippedSecondary; break;
            }
        },

        populateItemGridWithType: function (itemType) {
            this.equip.selectedItemType = itemType;
            var items = extern.getItemsOfType(itemType);
            this.populateItemGrid(items);
            
            this.equip.categoryLocKey = 'item_type_{0}{1}'.format(itemType, ((itemType === ItemType.Primary) ? '_' + this.classIdx : ''));
        },

        populateItemGridWithTagged: function (tag) {
            var items = extern.getTaggedItems(tag);
            this.populateItemGrid(items);
            this.equip.categoryLocKey = 'item_type_5';
        },

        populateItemGrid: function (items) {
            if (this.equip.mode === vueData.equip.equipModes.inventory) {
                items = items.filter(i => {
                    return extern.isItemOwned(i) || (i.is_available && i.unlock === "default");
                });
            } else {
                items = items.filter(i => {
                    return i.is_available && !extern.isItemOwned(i) && i.unlock !== "default";
                })
            }

            this.equip.showingItems = items;
        },

        workItBaby: function () {
            extern.poseWithItem(ItemType.Hat, this.posingHat);
            extern.poseWithItem(ItemType.Stamp, this.posingStamp);
            extern.poseWithItem(this.posingWeapon.item_type_id, this.posingWeapon);
        },

        onBackClick: function () {
            extern.saveEquipment();

            this.equip.showingWeaponType = ItemType.Primary;
            this.poseEquippedItems();

            if (!extern.inGame) {
                vueApp.switchToHomeUi();
            } else {
                extern.closeEquipInGame();
                vueApp.switchToGameUi();
            }

            vueApp.playSound('./sound/ui/ui_popupclose.mp3');
        },

        onItemTypeChanged: function (itemType) {
            this.switchItemType(itemType);
        },

        switchItemType: function (itemType) {
            if (itemType !== this.equip.selectedItemType) {
                if (itemType === ItemType.Primary || itemType === ItemType.Secondary) {
                    this.equip.showingWeaponType = itemType;
                }
                this.poseEquippedItems();
                this.populateItemGridWithType(itemType);
                if (this.equip.mode === this.equip.equipModes.inventory) {
                    this.selectEquippedItemForType();
                } else {
                    this.selectFirstItemInShop();
                }
            }
            if (!this.isInShop) {
                this.hideItemForSale();
                this.hideItemForSpecial();
            }
            vueApp.playSound('./sound/ui/ui_click.mp3');
        },

        onTaggedItemsClicked: function () {
            this.showTaggedItems(this.equip.specialItemsTag);
            this.selectFirstItemInShop();
            vueApp.playSound('./sound/ui/ui_click.mp3');
        },

        showTaggedItems: function (tag) {
            this.equip.selectedItemType = 'tagged';

            if (this.equip.mode === this.equip.equipModes.inventory && !this.ownsTaggedItems(this.equip.specialItemsTag)) {
                this.equip.mode = this.equip.equipModes.shop;
            }
            
            this.populateItemGridWithTagged(tag);
        },

        switchToInventory: function () {
            if (this.equip.selectedItemType === 'tagged' && this.equip.mode === this.equip.equipModes.shop) {
                if (!this.ownsTaggedItems(this.equip.specialItemsTag)) {
                    this.switchItemType(ItemType.Primary);
                }
            }

            this.equip.mode = this.equip.equipModes.inventory;
            this.hideItemForSale();
            this.hideItemForSpecial();
            this.poseEquippedItems();
            this.showItemsAfterEquipModeSwitch();
            this.selectEquippedItemForType();
            vueApp.playSound('./sound/ui/ui_toggletab.mp3');
        },

        ownsTaggedItems: function (tag) {
            return extern.getTaggedItems(tag).filter(i => {
                    return extern.isItemOwned(i);
                }).length > 0;
        },

        selectFirstItemInShop: function () {
            if (this.isInShop && this.equip.showingItems.length > 0) {
                this.selectItem(this.equip.showingItems[0]);
            }
        },

        switchToShop: function () {
            this.equip.mode = this.equip.equipModes.shop;
            this.showItemsAfterEquipModeSwitch();
            this.selectFirstItemInShop();
            vueApp.conditionalAnonWarningCall();
            vueApp.playSound('./sound/ui/ui_toggletab.mp3');
        },

        showItemsAfterEquipModeSwitch: function () {
            if (this.equip.selectedItemType !== 'tagged') {
                this.populateItemGridWithType(this.equip.selectedItemType);
            } else {
                this.showTaggedItems(this.equip.specialItemsTag)
            }
        },

        onEquippedTypeSelected: function (itemType) {
            this.equip.selectedItemType = itemType;
            if (this.equip.selectedItemType === ItemType.Primary || this.equip.selectedItemType === ItemType.Secondary) {
                this.equip.showingWeaponType = itemType;
            }
            this.switchToInventory();
        },

        onChangedClass: function () {
            this.hideItemForSale();
            this.hideItemForSpecial();

            this.updateEquippedItems();
            this.poseEquippedItems();
            this.populateItemGridWithType(this.equip.selectedItemType);
        },

        autoSelectItem: function (item) {
            if (extern.isItemOwned(item)) {
                this.switchToInventory();
            } else {
                this.switchToShop();
            }
            this.switchItemType(item.item_type_id);
            this.selectItem(item);
        },

        onItemSelected: function (item) {
            this.selectItem(item);
        },

        selectItem: function (item) {
            var selectingSame = hasValue(this.equip.selectedItem) && this.equip.selectedItem.id === item.id;
            var selectedId = selectingSame ? this.equip.selectedItem.id : null;
            var isWeapon = (item.item_type_id === ItemType.Primary || item.item_type_id === ItemType.Secondary);
            vueApp.playSound('./sound/ui/ui_click.mp3');

            if (selectingSame) {
                if (this.isInShop) {
                    // Revert to equipped weapon
                    item = this.$options[this.equip.selectedItem.item_type_id];
                } else {
                    // Take off hat or stamp
                    if (!isWeapon) {
                        item = null;
                        extern.removeItemType(this.equip.selectedItem.item_type_id);
                    }
                }
            }

            // Take off any items being tried on
            this.poseEquippedItems();

            this.equip.selectedItem = item;
            extern.tryEquipItem(item);
            this.updateEquippedItems();

            if (hasValue(item)) {
                this.poseWithItem(item);

                if (this.isInShop) {
                    switch (item.unlock) {
                        case "physical":
                            console.log('purchasing physical item');
                            
                            if ( !selectingSame ) {
                                this.offerItemForSpecial(item)
                                this.hideItemForSale();
                            } else {
                                this.hideItemForSpecial();
                            }
                            // this.$refs.physicalUnlockPopup.toggle();
                            break;
                        case "purchase":
                            if (!selectingSame) {
                                this.offerItemForSale(item);
                                this.hideItemForSpecial();
                            } else {
                                this.hideItemForSale();
                            }
                        break;
                    }
                }
            } else {
                this.poseEquippedItems();
                this.hideItemForSale();
                this.hideItemForSpecial();

            }
        },

        poseWithItem: function (item) {
            switch (item.item_type_id) {
                case ItemType.Hat: this.posingHat = item; break;
                case ItemType.Stamp: this.posingStamp = item; break;
                case ItemType.Primary:
                case ItemType.Secondary: this.posingWeapon = item; break;
            }

            this.workItBaby();
        },

        getButtonToggleClass: function (equipMode) {
            return (equipMode === this.equip.mode) ? 'btn_toggleon' : 'btn_toggleoff';
        },

        offerItemForSpecial: function(item) {
            return this.equip.physicalUnlockPopup.item = item;
        },

        hideItemForSpecial: function() {
            this.equip.physicalUnlockPopup.item = null;
        },

        offerItemForSale: function (item) {
            this.equip.buyingItem = item;
        },

        hideItemForSale: function () {
            this.equip.buyingItem = null;
            // this.equip.physicalUnlockPopup.item = null
        },

        onBuyItemClicked: function () {
            // If item is buying item show buyItemPopup or show physicalUnlockPopup
            this.equip.buyingItem ? this.$refs.buyItemPopup.toggle() : this.$refs.physicalUnlockPopup.toggle();
            this.equip.buyingItem ? extern.renderItemToCanvas(this.equip.buyingItem, this.$refs.buyItemCanvas) : null;
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },

        onBuyItemConfirm: function () {
            extern.api_buy(this.equip.buyingItem, this.boughtItemSuccess, this.boughtItemFailed);
            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        },

        boughtItemSuccess: function () {
            this.equip.selectedItem = this.equip.buyingItem;
            var itemType = this.equip.selectedItem.item_type_id;
            if (itemType === ItemType.Primary || itemType === ItemType.Secondary) {
                this.equip.showingWeaponType = itemType;
            }
            this.hideItemForSale();
            this.setup(this.equip.selectedItemType);
            this.updateEquippedItems();
            this.poseEquippedItems();
            this.selectEquippedItemForType();
        },

        boughtItemFailed: function () {
            vueApp.showGenericPopup('p_buy_error_title', 'p_buy_error_content', 'ok');
            vueApp.playSound('./sound/ui/ui_reset.mp3');
        },

        onRedeemClick: function () {
            this.$refs.redeemCodePopup.code = '';
            this.$refs.redeemCodePopup.toggle();
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },

        onRedeemCodeConfirm: function () {
            extern.api_redeem(this.equip.redeemCodePopup.code, this.redeemCodeSuccess, this.redeemCodeFailed);
            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        },

        redeemCodeSuccess: function (eggs, items) {
            this.populateItemGridWithType(this.equip.selectedItemType);

            this.giveStuffPopup.eggs = eggs;
            this.giveStuffPopup.items = items;
            this.$refs.giveStuffPopup.toggle();
        },

        redeemCodeFailed: function () {
            vueApp.showGenericPopup('p_redeem_error_title', 'p_redeem_error_content', 'ok');
            vueApp.playSound('./sound/ui/ui_reset.mp3');
        },

        onPhysicalUnlockConfirm: function () {
            window.open(this.equip.physicalUnlockPopup.item.item_data.physicalItemStoreURL, '_blank');
        },

        onColorChanged: function (colorIdx) {
            this.equip.colorIdx = colorIdx;
            extern.setShellColor(this.equip.colorIdx);
            vueApp.playSound('./sound/ui/ui_onchange.mp3');
        },

        onSwitchToShopClicked: function () {
            this.switchToShop();
        }
    },

    computed: {
        isInShop: function () {
            return (this.equip.mode === this.equip.equipModes.shop);
        },

        getGridClass: function () {
            return this.isInShop ? '' : 'equip_grid_short';
        }
    }
};
</script><script id="game-screen-template" type="text/x-template">
    <div>
        <account-panel id="game_account_panel" ref="accountPanel" :loc="loc" :eggs="eggs" :show-bottom="false" :show-corner-buttons="ui.showCornerButtons" :ui="ui"></account-panel>

        <div id="chickenBadge" ref="chickenBadge" style="display: none;"><img src="img/ico_chickenBadge.png"></div>

        <!-- Reticle -->
        <div id="reticleContainer">
            <div id="crosshairContainer">
                <div id="crosshair0" class="crosshair"></div>
                <div id="crosshair1" class="crosshair"></div>
                <div id="crosshair2" class="crosshair"></div>
                <div id="crosshair3" class="crosshair"></div>
            </div>

            <div id="shotReticleContainer">
                <div class="shotReticle black"></div>
                <div class="shotReticle black"></div>
                <div class="shotReticle white"></div>
                <div class="shotReticle white"></div>
            </div>

            <div id="readyBrackets">
                <div class="readyBracket"></div>
                <div class="readyBracket"></div>
                <div class="readyBracket"></div>
                <div class="readyBracket"></div>
            </div>
        </div>

        <!-- Scope -->
        <div id="scopeBorder">
            <div id="maskleft"></div>
            <div id="maskmiddle"></div>
            <div id="maskright"></div>
        </div>

        <!-- Best Streak -->
        <div id="best_streak_container"> 
            <!--<h3>{{ loc.ui_game_beststreak }}</h3>-->
            <h1 id="bestStreak">x0</h1>
        </div>

        <!-- Team Scores -->
        <div id="teamScores">
            <div id="teamScore2" class="teamScore red inactive">
                    <div id="teamScoreNum2" class="number">0</div>
                    <div class="teamLetter red" style="color: #f00;">R</div>
            </div>
            <div id="teamScore1" class="teamScore blue inactive">
                    <div id="teamScoreNum1" class="number">0</div>
                    <div class="teamLetter blue" style="color: #0af;">B</div>
            </div>
            <!--<div>
                    <img src="img/spatulaIcon.png" style="width: 3em; transform: rotate(60deg)">
            </div>-->
        </div>

        <!-- Weapon -->
        <div id="weaponBox">
            <div id="grenades">
                <img id="grenade3" class="grenade" src="img/ico_grenadeEmpty.png?v=1"/>
                <img id="grenade2" class="grenade" src="img/ico_grenadeEmpty.png?v=1"/>
                <img id="grenade1" class="grenade" src="img/ico_grenadeEmpty.png?v=1"/>
            </div>
            <h2 id="weaponName"></h2>
            <h2 id="ammo" class="shadow_grey"></h2>
        </div>

        <!-- Health -->
        <div id="health">
            <svg class="healthSvg">
                <circle id="healthBar" class="healthBar" cx="50%" cy="50%" r="2.15em" />
                <circle class="healthYolk" cx="50%" cy="50%" r="1.35em" />
            </svg>

            <div id="healthHp">100</div>
        </div>

        <!-- Spatula -->
        <img id="spatulaPlayer" src="img/spatulaIcon.png" />

        <!-- Grenade throw power -->
        <div id="grenadeThrowContainer">
            <div id="grenadeThrow"></div>
        </div>

        <!-- Kill -->
        <div id="killBox" class="shadow_grey">
            <h3>{{ loc.ui_game_youkilled }}</h3>
            <h2 id="KILLED_NAME"></h2>
            <h3 id="KILL_STREAK"></h3>
        </div>

        <!-- Death -->
        <div id="deathBox">
            <h3>{{ loc.ui_game_killedby }}</h3>
            <h2 id="KILLED_BY_NAME"></h2>
            <h3 id="respawnMessage"></h3>
        </div>

        <!-- Game messages -->
        <div id="gameMessage"></div>

        <!-- Chat -->
        <div id="chatOut" class="chat roundme_sm"></div>

        <input id="chatIn" class="chat roundme_sm" maxlength=64 tabindex=-1 placeholder="Press TAB to exit" onkeydown="extern.onChatKeyDown(event)"></input>

        <!-- Kill ticker -->
        <div id="killTicker" class="chat"></div>

        <!-- Spectator controls -->
        <div id="spectate">
            {{ loc.ui_game_spectating }}
        </div>

        <div id="serverAndMapInfo" class="shadow_grey"></div>

        <!-- Ingame UI Stuff --> 
        <div id="inGameUI">
            <div id="readouts" class="shadow_grey">
                {{ loc.ui_game_fps }}: <div id="FPS"></div><br>
                {{ loc.ui_game_ping }}: <div id="ping"></div>
            </div>

            <!-- Corner icon buttons -->
            <!--
            <div id="corner" style="float: right; margin-top: 0.5em;">
                    <div id="currentBalanceContainer" style="display: none; position: relative; left: -1em; top: 0.15em;">
                            <span id="currentBalance" style="display: inline-block; font-size: 1.7em; position: relative; top: -0.25em; left: -0.1em; color: white;"></span>
                            boopdiddyboop<img src="img/egg_icon.png" style="width: 1.6em; height: 2em;" />
                    </div>
                    <div id="cornerButtons" style="display: none; margin-bottom: 0.5em; text-align: right; float: right;">
                            <-<img id="homeButton" style="display: none; margin-right: 0.5em;" title="Home" class="icon" src="img/home.png?v=1" onclick="extern.showMainMenuConfirm()" />
                            <img id="friendsButton" style="display: none; margin-right: 0.5em;" title="Invite friends" class="icon" src="img/friends.png?v=1" onclick="extern.inviteFriends()" />        
                            <img style="margin-right: 0.5em;" title="Feedback" class="icon" src="img/feedback.png?v=1" onclick="extern.showFeedbackForm()" />
                            <img style="margin-right: 0.5em;" title="Settings" class="icon" src="img/settings.png?v=1" onclick="extern.openSettingsMenu()" />
                            <img class="icon" title="Toggle fullscreen" src="img/fullScreen.png?v=1" onclick="extern.toggleFullscreen()" /> ->
                    </div>
            </div>
            -->
        </div>

        <!-- Popup: Mute/Boot Player -->
        <small-popup id="playerActionsPopup" ref="playerActionsPopup" @popup-cancel="onPlayerActionsCancel" @popup-closed="onPlayerActionsCancel" :hide-confirm="true">
            <template slot="header">{{ playerActionsPopup.playerName }}</template>
            <template slot="content">
                <p>{{ loc.ui_game_playeractions_header }}</p>
                <h4 class="ss_button btn_medium btn_blue bevel_blue" v-on:click="onMuteClicked">{{ muteButtonLabel }}</h4>
                <h4 class="ss_button btn_medium btn_yolk bevel_yolk" v-if="playerActionsPopup.isGameOwner" v-on:click="onBootClicked">{{ loc.ui_game_playeractions_boot }}</h4>
            </template>
            <template slot="cancel">{{ loc.cancel }}</template>
        </small-popup>

        <!-- Popup: Switch Team -->
        <small-popup id="switchTeamPopup" ref="switchTeamPopup" @popup-cancel="onSwitchTeamCancel" :overlay-close="false" @popup-closed="onSwitchTeamCancel" @popup-confirm="onSwitchTeamConfirm">
            <template slot="header">{{ loc.p_switch_team_title }}</template>
            <template slot="content">
                <h4 class="roundme_sm" :class="newTeamColorCss">{{ newTeamName }} <i class="fa fa-flag"></i></h4>
                <p>{{ loc.p_switch_team_text }}</p>
            </template>
            <template slot="cancel">{{ loc.no }}</template>
            <template slot="confirm">{{ loc.yes }}</template>
        </small-popup>

        <!-- Popup: Share Link -->
        <small-popup id="shareLinkPopup" ref="shareLinkPopup" :popup-model="game.shareLinkPopup" @popup-confirm="onShareLinkConfirm" @popup-closed="onShareLinkClosed">
            <template slot="header">{{ loc.p_sharelink_title }}</template>
            <template slot="content">
                <p>{{ loc.p_sharelink_text }}</p>
                <p><input ref="shareLinkUrl" type="text" class="ss_field ss_margintop ss_marginbottom fullwidth" v-model="game.shareLinkPopup.url" @focus="$event.target.select()"></p>
            </template>
            <template slot="cancel">{{ loc.close }}</template>
            <template slot="confirm">{{ loc.p_sharelink_copylink }}</template>
        </small-popup>

        <!-- Popup: Leave Game Confirm -->
        <small-popup id="leaveGameConfirmPopup" ref="leaveGameConfirmPopup" :overlay-close="false" :hide-close="true" @popup-confirm="onLeaveGameConfirm" @popup-cancel="onLeaveGameCancel">
            <template slot="header">{{ loc.leave_game_title }}</template>
            <template slot="content">
                <p>{{ loc.leave_game_text }}</p>
            </template>
            <template slot="cancel">{{ loc.no }}</template>
            <template slot="confirm">{{ loc.yes }}</template>
        </small-popup>

        <div id="inGameScaler">

            <div class="player__container">
            <!-- Player List -->
                <div id="playerSlot" class="playerSlot" style="display: none">
                    <div style="
                        display: table-cell;
                        border-radius: 0.2em;
                        padding-top: 0.05em; padding-bottom: 0.05em;
                        padding-left: 0.5em; padding-right: 0.5em;
                        overflow-y: hidden;
                        font-weight: bold;
                    ">
                        <span></span> <!-- Name -->
                        <span style="padding-left: 1em"></span> <!-- Score -->
                    </div>
                    <div style="display: table-cell;"></div> <!-- Icons -->
                </div>
                <div id="playerList"></div>
            </div>
            <!-- end .player__container -->

            <div class="pause-popup--container">
                <!-- Popup: Pause -->
                <large-popup id="pausePopup" ref="pausePopup" hide-close="true" :overlay-close="false" :overlay-class="ui.overlayClass.inGame">
                    <template slot="content">
                        <div id="pausePopupInnards" class="box_blue2 roundme_sm fullwidth f_row">
                            
                            <div id="pauseButtons">
                                <button @click="onHomeClicked" class="ss_button btn_blue bevel_blue"><i class="fa fa-home"></i> {{ loc.p_pause_home }}</button>
                                <button @click="onEquipClicked()" class="ss_button btn_blue bevel_blue"><i class="fas fa-star"></i> {{ loc.p_pause_equipment }}</button>
                                <!-- Don't have leaderboards yet <button class="ss_button btn_blue bevel_blue"><i class="fa fa-trophy"></i> {{ loc.p_pause_leaderboards }}</button> -->
                                <!-- <button class="ss_button btn_blue bevel_blue"><i class="fa fa-shopping-cart"></i> {{ loc.p_pause_shop }}</button> -->
                                <button @click="onHelpClicked" class="ss_button btn_blue bevel_blue"><i class="fa fa-question"></i> {{ loc.p_pause_help }}</button>
                                <button @click="onShareLinkClicked" class="ss_button btn_blue bevel_blue"><i class="fa fa-link"></i> {{ loc.p_pause_sharelink }}</button>
                                
                                <button @click="onSettingsClicked" class="ss_button btn_blue bevel_blue"><i class="fa fa-cog"></i> {{ loc.p_pause_settings }}</button>
                            </div>
                            
                            <div id="popupTipDay" class="popupTipDay roundme_sm">
                                <h3><i class="fa fa-lightbulb fa-lg"></i> {{ loc.p_pause_tipoftheday }}</h3>
                                <p>{{ (loc.tip_ofthe_day ? loc.tip_ofthe_day[game.tipIdx] : '') }}</p>
                                <div id="btn_horizontal" class="pause-popup--btn-group">
                                    <div class="btn-container">
                                        <button v-show="isTeamGame" @click="onSwitchTeamClicked" class="ss_button btn__team_switch" :class="teamColorCss">{{ teamName }} <i class="fa fa-flag"></i></button>
                                    </div>
                                    <div class="btn-container">
                                        <button @click="onSpectateClicked()" class="ss_button btn_blue bevel_blue btn_sm" v-show="!isRespawning"><i class="fas fa-eye"></i> {{ loc.p_pause_spectate }}</button>
                                        <button @click="onPlayClicked()" class="ss_button btn_green bevel_green btn_sm" v-show="!isRespawning"><i class="fa fa-play"></i> {{ loc.p_pause_play }}</button>
                                        <button class="fullwidth btn__respawning" v-show="isRespawning">{{ game.respawnTime }}</button>
                                    </div>
                                </div>
                            </div>
                            
                        </div>
                        
                        <div id="pauseAdPlacement" ref="pauseAdPlacement"></div>
                    </template>
                </large-popup>
            </div>
            <!-- .pause-popup--container -->
        
            <!-- <div id="testbaby"></div> -->
    
        </div>
        <!-- end #inGameScaler -->

    </div>
</script>

<script>
var comp_game_screen = {
    template: '#game-screen-template',
    components: {
        'account-panel': comp_account_panel,
    },

    data: function () {
        return vueData;
    },

    created: function () {
        window.addEventListener('resize', this.resizeBannerAdTagForGame);
    },

    destroyed: function () {
        window.removeEventListener('resize', this.resizeBannerAdTagForGame);
    },

    methods: {
        placeBannerAdTagForGame: function (tagEl) {
            this.$refs.pauseAdPlacement.appendChild(tagEl);
        },

        showGameMenu: function () {
            this.game.tipIdx = this.loc.tip_ofthe_day
                ? Math.randomInt(0, this.loc.tip_ofthe_day.length)
                : 0;
            this.game.gameType = extern.gameType;
            this.$refs.pausePopup.show();
            vueData.ui.showCornerButtons = true;
            setTimeout(() => this.resizeBannerAdTagForGame(), 1);
        },

        hideGameMenu: function () {
            this.$refs.pausePopup.hide();
        },

        onHomeClicked: function () {
            this.hideGameMenu();
            this.$refs.leaveGameConfirmPopup.show();
            vueApp.playSound('./sound/ui/ui_click.mp3');
        },

        onLeaveGameConfirm: function () {
            this.leaveGame();
        },

        onLeaveGameCancel: function () {
            this.showGameMenu();
        },

        leaveGame: function () {
            // clientGame.js manipulates chickenBadge element directly to hide/show it
            this.$refs.chickenBadge.style.display = 'none';

            vueApp.showSpinner();
            document.body.style.overflow = 'visible';
            window.scrollY = 0;
            this.hidePopupsIfGameCloses();
            extern.leaveGame(this.afterLeftGame);
            vueData.ui.showCornerButtons = true;
            // OneSignal elements are not part of the Vue app
            var oneSignalBell = document.getElementById('onesignal-bell-container');
            if (oneSignalBell) {
                oneSignalBell.style.display = 'inline-block';
            }
        },

        hidePopupsIfGameCloses: function() {
            const gamePopups = vueApp.$refs.gameScreen.$children;
            if (Array.isArray(gamePopups)) {
                gamePopups.forEach( gamePopup => {;
                    if ( gamePopup.isShowing === true && gamePopup.$el.id !== 'pausePopup' ) {
                        gamePopup.close();
                        console.log(`Closing ${gamePopup.$el.id}`);
                    }
                });
            }
        },

        afterLeftGame: function () {
            vueApp.hideSpinner();
            vueApp.switchToHomeUi();
        },

        onHelpClicked: function () {
            this.hideGameMenu();
            vueApp.showHelpPopup();
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },

        onShareLinkClicked: function () {
            extern.inviteFriends();
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },

        onSettingsClicked: function () {
            this.hideGameMenu();
            vueApp.showSettingsPopup();
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
        },

        onShareLinkConfirm: function () {
            extern.copyFriendCode(this.$refs.shareLinkUrl);
        },

        onShareLinkClosed: function () {
            this.showGameMenu();
        },

        onEquipClicked: function () {
            this.hideGameMenu();
            extern.openEquipInGame();
            vueApp.switchToEquipUi();
            vueApp.playSound('./sound/ui/ui_equip.mp3');
        },

        onSwitchTeamClicked: function () {
            this.hideGameMenu();
            vueApp.playSound('./sound/ui/ui_popupopen.mp3');
            this.$refs.switchTeamPopup.show();
        },

        onSwitchTeamCancel: function () {
            this.showGameMenu();
        },

        onSwitchTeamConfirm: function () {
            extern.switchTeam();
            this.showGameMenu();
        },

        onPlayClicked: function () {
            this.hideGameMenu();
            vueData.ui.showCornerButtons = false;
            extern.respawn();
            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        },

        onSpectateClicked: function () {
            this.hideGameMenu();
            vueData.ui.showCornerButtons = false;
            extern.enterSpectatorMode();
            vueApp.playSound('./sound/ui/ui_playconfirm.mp3');
        },

        showPlayerActionsPopup: function () {
            this.hideGameMenu();
            this.$refs.playerActionsPopup.show();
        },

        onPlayerActionsCancel: function () {
            this.showGameMenu();
        },

        onMuteClicked: function () {
            this.$refs.playerActionsPopup.hide();
            this.playerActionsPopup.muteFunc();
        },

        onBootClicked: function () {
            this.$refs.playerActionsPopup.hide();
            this.playerActionsPopup.bootFunc();
        },

        resizeBannerAdTagForGame: function() {
            const pauseAdPlacement = document.getElementById('pauseAdPlacement');
            const rect = document.getElementById('pausePopup').getBoundingClientRect();

            pauseAdPlacement.style.top = (rect.height).toString() + 'px';

            if (rect.width < 970) {
                pauseAdPlacement.style.transform = ' scale(' + (rect.width / 970) + ') translateX(-50%)';
            } else {
                pauseAdPlacement.style.transform = ' scale(1) translateX(-50%)';
            }

        }
    },

    computed: {
        isRespawning: function () {
            return this.game.respawnTime > 0;
        },

        isTeamGame: function () {
            // Would be better to use the same enum as the client game code
            return this.game.gameType !== 0;
        },

        teamColorCss: function () {
            return this.game.team === this.ui.team.blue ? 'blueTeam btn_red bevel_red' : 'redTeam btn_blue bevel_blue';
        },

        teamName: function () {
            return this.game.team === this.ui.team.blue ? this.loc.p_pause_joinred : this.loc.p_pause_joinblue;
        },

        newTeamColorCss: function () {
            return this.game.team === this.ui.team.blue ? 'redTeam btn_red' : 'blueTeam btn_blue';
        },

        newTeamName: function () {
            return this.game.team === this.ui.team.blue ? this.loc.team_red : this.loc.team_blue;
        },

        muteButtonLabel: function () {
            return this.playerActionsPopup.muted ? this.loc.ui_game_playeractions_unmute : this.loc.ui_game_playeractions_mute;
        }
    }
};
</script>

<script>

function startVue(languageCode, locData) {

    vueData.extern = extern;
    vueData.loc = locData;
    
    vueApp = new Vue({
        el: '#app',
        components: {
            'dark-overlay': comp_dark_overlay,
            'light-overlay': comp_light_overlay,
            'spinner-overlay': comp_spinner_overlay,
            'gdpr': comp_gdpr,
            'settings': comp_settings,
            'help': comp_help,
            'egg-store': comp_egg_store,
            'item': comp_item,
            'home-screen': comp_home_screen,
            'equip-screen': comp_equip_screen,
            'game-screen': comp_game_screen,
            'gold-chicken-popup': comp_gold_chicken_popup,
            'chicken-nugget-popup': comp_chicken_nugget_popup
        },

        data: vueData,

        createdTime: null,
        mountedTime: null,
        fullyRenderedTime: null,
        
        multisizeAdTag: null,

        created () {
            console.log('Vue instance created');
            createdTime = performance.now();
            // Create localStorage for language on vueApp created lifecyle if none present
            if (! getStoredString('selectedLanguage', null) ){
               localStorage.setItem('selectedLanguage', languageCode);
            }
            // currentLanguageCode is set the localStorage selecetedLanguage but just in case, set it to the default
            this.currentLanguageCode = getStoredString('selectedLanguage', null) ? localStorage.getItem('selectedLanguage') : languageCode;
            // run the method to update the current languge
            this.changeLanguage(this.currentLanguageCode);
        },

        mounted () {
            console.log('Vue instance mounted');
            mountedTime = performance.now();
            console.log('create -> mount time (ms): ' + (mountedTime - createdTime));

            this.currentGameType = extern.gameType;

            this.$options.multisizeAdTag = useAdManager 
                ? document.getElementById('div-gpt-ad-5141196-1')
                : document.getElementById('shellshock-io_multisize');

            // Cannot modify data within the mounted hook, so wait until next tick
            this.$nextTick(function () {
                fullyRenderedTime = performance.now();
                console.log('mounted -> fully rendered time (ms): ' + (fullyRenderedTime - mountedTime));
                console.log('created -> fully rendered time (ms): ' + (fullyRenderedTime - createdTime));

                this.ready = true;
                
                this.placeBannerAdTagForNugget(this.$options.multisizeAdTag);
                this.showSpinner('ui_game_loading', 'ui_game_waitforit');
                //this.playMusic();
                
                extern.continueStartup();
            });
        },

        methods: {
            getCanvas: function () {
                return this.$refs.canvas;
            },

            playMusic: function () {
                myAudio = new Audio('./sound/theme.mp3');
                // Uncomment for looping.
                // myAudio.addEventListener('ended', function() {
                //     this.currentTime = 0;
                //     this.play();
                // }, false);
                myAudio.volume = this.volume;
                myAudio.play();
            },

            playSound: function (sound) {
                if(sound) {
                    var audio = new Audio(sound);
                    audio.volume = this.volume;
                    audio.play();
                }
            },

            changeLanguage: function (languageCode) {
                extern.getLanguageData(languageCode, this.setLocData);
            },

            setLocData: function (languageCode, newLocData) {
                this.currentLanguageCode = getStoredString('selectedLanguage', null) ? localStorage.getItem('selectedLanguage') : languageCode;
                this.loc = newLocData;
            },

            setPlayerName: function (playerName) {
                this.playerName = playerName;
            },

            showSpinner: function (headerLocKey, footerLocKey) {
                this.$refs.spinnerOverlay.show(headerLocKey, footerLocKey);
            },

            showSpinnerLoadProgress: function (percent) {
                this.$refs.spinnerOverlay.showSpinnerLoadProgress(percent);
            },

            hideSpinner: function () {
                this.$refs.spinnerOverlay.hide();
            },

            onSettingsPopupOpened: function () {
                this.$refs.settings.captureOriginalSettings();
            },

            onSettingsX: function () {
                this.$refs.settings.applyOriginalSettings();
                this.$refs.settings.cancelLanguageSelect();
            },

            onNoAnonPopupConfirm: function () {
                this.showFirebaseSignIn();
            },

            onSharedPopupClosed: function () {
                // If in-game, show game menu after closing the popup
                //this.playSound('./sound/ui/ui_popupclose.mp3');
                if (this.ui.showScreen === this.ui.screens.game && extern.inGame) {
                    this.showGameMenu();
                }
            },

            onGiveStuffComplete: function () {
                this.$refs.giveStuffPopup.toggle();
            },

            onPrivacyOptionsOpened: function () {
                this.showPrivacyPopup();
            },
            /**
             * Creates a generic popup that passes content 3 data options to slots on the genericPopup smallPopup
             * @param titleLockKey mixed - popup header text
             * @param contentLocKey mixed- popup content
             * @param confirmLocKey mixed - popup button text
             */
            showGenericPopup: function (titleLocKey, contentLocKey, confirmLocKey, hideBackgroundPopup) {
                this.genericMessagePopup.titleLocKey = titleLocKey;
                this.genericMessagePopup.contentLocKey = contentLocKey;
                this.genericMessagePopup.confirmLocKey = confirmLocKey;
                this.hidePausePopupIfGenericPopupOpen();
                this.$refs.genericPopup.show();

                // vueApp.setDarkOverlay();
            },
            hidePausePopupIfGenericPopupOpen: function() {

                if (!this.$refs.gameScreen.$refs.pausePopup && $refs.gameScreen.$refs.pausePopup.isShowing === false) {
                    return;
                }

                return this.$refs.gameScreen.$refs.pausePopup.hide();
            },
            showOpenUrlPopup: function (url, titleLocKey, content, confirmLocKey, cancelLocKey) {
                console.log('title: ' + this.loc[titleLocKey]);
                console.log('confirm: ' + this.loc[confirmLocKey]);
                console.log('cancel: ' + this.loc[cancelLocKey]);

                this.openUrlPopup.url = url;
                this.openUrlPopup.titleLocKey = titleLocKey;
                this.openUrlPopup.content = content;
                this.openUrlPopup.confirmLocKey = confirmLocKey;
                this.openUrlPopup.cancelLocKey = cancelLocKey;
                this.$refs.openUrlPopup.show();
            },

            onOpenUrlPopupConfirm: function () {
                extern.openUrlAndGiveReward();
            },

            showMissingFeaturesPopup: function () {
                this.ui.showScreen = -1;
                this.$refs.missingFeaturesPopup.show();
            },

            showFirebaseSignIn: function () {
                this.$refs.homeScreen.showSignIn();
            },

            hideFirebaseSignIn: function () {
                this.$refs.homeScreen.$refs.firebaseSignInPopup.hide();
            },

            showCheckEmail: function () {
                this.$refs.homeScreen.$refs.checkEmailPopup.show();
            },

            hideCheckEmail: function () {
                this.$refs.homeScreen.$refs.checkEmailPopup.hide();
            },

            showResendEmail: function () {
                this.$refs.homeScreen.$refs.resendEmailPopup.show();
            },

            hideResendEmail: function () {
                this.$refs.homeScreen.$refs.resendEmailPopup.hide();
            },

            showChickenPopup: function () {
                this.$refs.goldChickenPopup.show();
            },

            hideChickenPopup: function () {
                this.$refs.goldChickenPopup.hide();
            },

            showHelpPopup: function () {
                this.hideGameMenu();
                this.$refs.helpPopup.show();
            },

            showAttentionPopup: function () {
                this.hideGameMenu();
                this.$refs.anonWarningPopup.show();
            },

            hideHelpPopup: function () {
                this.$refs.helpPopup.hide();
            },

            showSettingsPopup: function () {
                this.hideGameMenu();
                this.$refs.settingsPopup.show();
                extern.settingsMenuOpened();
            },

            hideSettingsPopup: function () {
                this.$refs.settingsPopup.hide();
            },

            showEggStorePopup: function () {
                this.hideGameMenu();
                this.$refs.eggStorePopup.show();
            },

            hideEggStorePopup: function () {
                this.$refs.eggStorePopup.hide();
            },

            showChangelogPopup: function () {
                this.$refs.changelogPopup.show();
            },

            hideChangelogPopup: function () {
                //this.playSound('./sound/ui/ui_popupclose.mp3');
                this.$refs.changelogPopup.hide();
            },

            showGiveStuffPopup: function (titleLoc, eggs, items) {
                this.giveStuffPopup.titleLoc = titleLoc;
                this.giveStuffPopup.eggs = eggs;
                this.giveStuffPopup.items = items;
                this.$refs.giveStuffPopup.show();
            },

            showShareLinkPopup: function (url) {
                this.hideGameMenu();
                this.game.shareLinkPopup.url = url;
                this.$refs.gameScreen.$refs.shareLinkPopup.show();
            },

            showJoinPrivateGamePopup: function (code) {
                this.$refs.homeScreen.$refs.playPanel.showJoinPrivateGamePopup(code);
            },

            switchToHomeUi: function () {
                this.ui.showScreen = this.ui.screens.home;

                this.placeBannerAdTagForNugget(vueApp.$options.multisizeAdTag);
            },

            switchToEquipUi: function () {
                console.log('switchToEquipUi called');
                this.$refs.equipScreen.setup();
                this.$refs.equipScreen.switchToInventory();
                this.ui.showScreen = this.ui.screens.equip;
            },

            switchToGameUi: function (isGameOwner) {
                this.ui.showScreen = this.ui.screens.game;
                this.game.isGameOwner = isGameOwner;
                
                // The ad tags are outside of the Vue app; manipulate the DOM directly
                this.$refs.gameScreen.placeBannerAdTagForGame(vueApp.$options.multisizeAdTag);

                this.showGameMenu();
            },

            showGameMenu: function () {
                this.hideSpinner();
                this.$refs.gameScreen.showGameMenu();
            },

            hideGameMenu: function () {
                this.$refs.gameScreen.hideGameMenu();
            },

            onMiniGameCompleted: function () {
                this.$refs.homeScreen.onMiniGameCompleted();
            },

            setShellColor: function (colorIdx) {
                this.equip.colorIdx = colorIdx;
            },

            setAccountUpgraded: function (upgraded) {
                this.isUpgraded = upgraded;
                this.equip.extraColorsLocked = !this.isUpgraded;
            },

            setDarkOverlay: function (visible, overlayClass) {
                this.$refs.darkOverlay.show = visible;
                this.$refs.darkOverlay.overlayClass = overlayClass;
            },

            setLightOverlay: function (visible, overlayClass) {
                this.$refs.lightOverlay.show = visible;
                this.$refs.darkOverlay.overlayClass = overlayClass;
            },

            authCompleted: function () {
                this.hideFirebaseSignIn();
                if (extern.isGameReady) {
                    this.hideSpinner();
                    this.setDarkOverlay(false);
                }
            },

            showItemOnEquipScreen: function (item) {
                this.switchToEquipUi();
                this.$refs.equipScreen.autoSelectItem(item);
            },

            showTaggedItemsOnEquipScreen: function (tag) {
                this.switchToEquipUi();
                this.$refs.equipScreen.showTaggedItems(tag);
            },

            useHouseAdSmall: function (smallHouseAd) {
                this.ui.houseAds.small = smallHouseAd;
            },

            useHouseAdBig: function (bigHouseAd) {
                this.ui.houseAds.big = bigHouseAd;
            },

            denyAnonUser: function () {
                this.$refs.noAnonPopup.show();
            },

            showGdrpNotification: function () {
                this.$refs.gdpr.show();
            },

            showPrivacyPopup: function () {
                this.hideSettingsPopup();
                this.$refs.privacyPopup.show();
            },

            hidePrivacyPopup: function () {
                this.$refs.privacyPopup.hide();
                this.showSettingsPopup();
            },

            ofAgeChanged: function () {
                extern.setOfAge(this.isOfAge);
                this.playSound('./sound/ui/ui_onchange.mp3');
            },

            targetedAdsChanged: function () {
                extern.setTargetedAds(this.showTargetedAds);
                this.playSound('./sound/ui/ui_onchange.mp3');
            },

            setPrivacySettings: function (ofAge, targetedAds) {
                this.isOfAge = ofAge;
                this.showTargetedAds = targetedAds;
            },

            gameJoined: function (gameType, team) {
                this.game.gameType = gameType;
                this.setTeam(team);
            },

            setTeam: function (team) {
                if (hasValue(team)) {
                    this.game.team = team;
                }
            },

            showGoldChickenPopup: function () {
                this.$refs.goldChickenPopup.show();
            },

            hideGoldChickenPopup: function () {
                this.$refs.goldChickenPopup.hide();
            },

            showNuggetPopup: function () {
                this.$refs.nuggetPopup.show();
                this.$refs.chickenNugget.loadMiniGame();
            },

            hideNuggetPopup: function () {
                this.$refs.nuggetPopup.hide();
                this.$refs.chickenNugget.unloadMiniGame();
            },

            onMiniGameCompleted: function () {
                this.$refs.chickenNugget.onMiniGameCompleted();
            },

            placeBannerAdTagForNugget: function (tagEl) {
                this.$refs.chickenNugget.placeBannerAdTag(tagEl);
            },

            useSpecialItemsTag: function (tag) {
                this.equip.specialItemsTag = tag;
                this.equip.showSpecialItems = true;
            },

            disableSpecialItems: function () {
                this.equip.showSpecialItems = false;
            },

            setUiSettings: function (settings) {
                this.$refs.settings.setSettings(settings);
            },

            leaveGame: function () {
                this.$refs.gameScreen.leaveGame();
            },

            showPlayerActionsPopup: function (slot) {
                this.playerActionsPopup = slot;
                this.$refs.gameScreen.showPlayerActionsPopup();
            },
            anonWarningPopupConfrim: function() {
                const anonWarnConfrimed = localStorage.getItem('anonWarningConfirmed');
                return anonWarnConfrimed === null && localStorage.setItem('anonWarningConfirmed', true);
            },
            conditionalAnonWarningCall: function() {
                const anonWarnConfrimed = localStorage.getItem('anonWarningConfirmed');
                return anonWarnConfrimed === null && vueApp.showAttentionPopup();
            },
            needMoreEggsPopupCall: function() {
                this.$refs.needMoreEggsPopup.show();
            }
        }
    });
}
</script>
    </body>
</html>
Source Code

Nend.io

<!DOCTYPE html>
<html>
    <head>
        <title>Nend.io</title>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="description" content="Survive to the city, upgrade your skill, live, age and prepare the next generation"/>
        <meta name="keywords" content="nend.io, mmo, online game, flash, canvas, html5, nend, life, city, life simulation, age, baby, family, street"/>
        <meta property="og:title" content="Nend.io - The Never Ending game"/>
        <meta property="og:description" content="Survive to city! Live, age and prepare the next generation."/>
        <meta property="og:url" content="https://nend.io"/>
        <meta property="og:site_name" content="nend.io"/>
        <meta property="og:image" content="https://nend.io/img/banner.png"/>
        <meta property="og:image:width" content="849"/>
        <meta property="og:image:height" content="488"/>
        <meta name="twitter:card" content="summary_large_image"/>
        <meta name="twitter:site" content="@nendio"/>
        <meta name="twitter:creator" content="@lapamauve"/>
        <meta name="twitter:url" content="https://nend.io"/>
        <meta name="twitter:title" content="Nend.io - The Never Ending game"/>
        <meta name="twitter:description" content="Survive to city! Live, age and prepare the next generation."/>
        <meta name="twitter:image" content="https://nend.io/img/banner.png"/>
        <meta name="mobile-web-app-capable" content="yes"/>
        <meta name="apple-mobile-web-app-capable" content="yes"/>
        <meta name="robots" content="index, follow"/>
        <meta name="revisit-after" content="3 days"/>
        <meta name="googlebot" content="all"/>
        <link rel="icon" type="image/png" href="img/favicon.png"/>
        <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Ubuntu:500,700"/>
        <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Press+Start+2P"/>
        <link rel="stylesheet" type="text/css" href="css/style.css"/>
    </head>

    <body id="bod">

        <canvas id="can"></canvas>

        <script src="js/client.1.2009.min.js"></script>

        <div id="nickname">

            <input id="nicknameInput" type="text" placeholder="Nickname" maxLength="16">
            
        </div>

        <div id="play">

            <div id="playButton"> PLAY </div>
            
        </div>

        <div id="seeMore">

            <a style="text-decoration: none; color : #595388;" href="./changelog/" target="_blank">
            <div class="seeMoreActive">SEE MORE</div>
            </a>
            
        </div>

        <div id="terms">

            <a class="link" href="http://nend.io/termsofuse" target="blank">Terms of Use</a> - <a class="link" href="http://nend.io/privacy" target="blank">Privacy</a>
            
        </div>

        <div id="serverList">

            <select id="servers">
                  <option disabled>Paris 3000 players</option>
                  <option>Paris - 200 players</option>
                  <option>Paris - 2800 players</option>
             </select>
            
        </div>

        <div id="howtoplay">

            
            HOW TO PLAY ?
            <br /><br />
            
            <div id="resumeHowToPlay">
            <div class="resume"> The city survival game:</div>
            <div class="resume"> Upgrade your skills </div>
            <div class="resume"> Buy and sell buildings</div>
            <div class="resume"> Be the richest</div>
            </div>
            
            <br />
            COMMANDS
            <br /><br />
            
            <div id="commandsHowToPlay">
            <div class="commands"> <span id="arrowHowToPlay" class="subcommands">ARROW KEY</span> or <span id="wasdHowToPlay"class="subcommands">WASD</span> to move </div>
            <div class="commands"> <span id="leftHowToPlay" class="subcommands">LEFT CLICK</span> to hit</div>
            <div class="commands"> <span id="enterHowToPlay"class="subcommands">ENTER</span> to chat</div>
            <div class="commands"> <span id="eHowToPlay" class="subcommands">E</span> or <span id="spaceHowToPlay" class="subcommands">SPACE</span> to interact</div>
            <div class="commands"> <span id="mHowToPlay" class="subcommands">M</span> for Map</div>
            <div class="commands"> <span id="rightHowToPlay" class="subcommands">RIGHT CLICK</span> to delete items</div>
            
            <br /><br />
            
            </div>
            
            
            <!-- Global site tag (gtag.js) - Google Analytics -->
            <script async src="https://www.googletagmanager.com/gtag/js?id=UA-78561996-4"></script>
            <script>
              window.dataLayer = window.dataLayer || [];
              function gtag(){dataLayer.push(arguments);}
              gtag('js', new Date());
            
              gtag('config', 'UA-78561996-4');
            </script>
            
        </div>

        <div id="otherGames">

            Our Other Games
            
        </div>

        <div id="authors">

            <a class="link" href="http://nend.io/authors" target="blank" style="color: #EEC0FD;font-weight: 900;">Authors</a> -
            
        </div>

        <div id="advert">

            <script async src="//api.adinplay.com/player/v2/NND/nend.io/player.min.js"></script>
            <script async src="//api.adinplay.com/display/pub/NND/nend.io/display.min.js"></script>
            <div id='nend-io_300x250'>
                  <script type='text/javascript'>
                    var aiptag = aiptag || {};
                    aiptag.cmd = aiptag.cmd || [];
                    aiptag.cmd.display = aiptag.cmd.display || [];
                    aiptag.cmd.display.push(function() { aipDisplayTag.display('nend-io_300x250'); });
                  </script>
            </div>
            
        </div>

        <div id="preroll">

            
        </div>

        <div id="chat">

            <input id="chatInput" type="text" placeholder="Enter text..." maxLength="60">
            
        </div>

    </body>
</html>
Source Code

Hexarena.io

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta
      name="description"
      content="HexArena.io is a 100% free multiplayer, live action, strategy game."
    />
    <meta
      property="og:description"
      content="HexArena.io is a 100% free multiplayer, live action, strategy game."
    />
    <meta property="og:title" content="HexArena.io" />
    <meta property="og:url" content="https://hexarena.io" />
    <meta
      property="og:image"
      content="https://hexarena.io/static/images/og-image.png"
    />
    <meta property="og:image:width" content="1200" />
    <meta property="og:image:height" content="630" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>HexArena.io</title>
    <link rel="icon" type="image/x-icon" href="/static/favicon/96x96.png" />
    <link
      href="https://fonts.googleapis.com/css?family=Montserrat:200,300,400,500,600,700'"
      rel="stylesheet"
    />

    <!-- Sentry -->
    <script
      src="https://browser.sentry-cdn.com/5.0.7/bundle.min.js"
      crossOrigin="anonymous"
    ></script>
    <script>
      const getEnvironment = () => {
        switch (window.location.hostname) {
          case 'localhost':
            return 'local'
          case 'dev.hexarena.io':
            return 'development'
          case 'hexarena.io':
            return 'production'
          default:
            return 'unknown-environment'
        }
      }
      Sentry.init({
        dsn: 'https://28bb77120c0b45a991f6c251a58ffa63@sentry.io/1438180',
        environment: getEnvironment(),
      })
    </script>

    <!-- Google Analytics -->
    <script
      async
      src="https://www.googletagmanager.com/gtag/js?id=UA-68180597-3"
    ></script>
    <script>
      window.dataLayer = window.dataLayer || []
      function gtag() {
        dataLayer.push(arguments)
      }
      gtag('js', new Date())
      gtag('config', 'UA-68180597-3')
    </script>

    <!-- Facebook SDK -->
    <script>
      window.fbAsyncInit = function() {
        FB.init({
          appId: '2146819318950261',
          cookie: true,
          xfbml: true,
          version: 'v3.3',
        })

        FB.AppEvents.logPageView()
      }
      ;(function(d, s, id) {
        var js,
          fjs = d.getElementsByTagName(s)[0]
        if (d.getElementById(id)) {
          return
        }
        js = d.createElement(s)
        js.id = id
        js.src = 'https://connect.facebook.net/en_US/sdk.js'
        fjs.parentNode.insertBefore(js, fjs)
      })(document, 'script', 'facebook-jssdk')
    </script>
  </head>

  <body>
    <div id="root"></div>
  <script type="text/javascript" src="bundle.1.53.3.js"></script></body>
</html>
Source Code

Update more in the few days

posted @ 2019-08-23 14:27  SSFLRK  阅读(400)  评论(0)    收藏  举报