Website's Game source code
A Darkroom by

<!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>
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)"> {{ loc.p_settings_of_age }}<br> <input id="targetedAdsCheck" type="checkbox" v-model="showTargetedAds" @change="targetedAdsChanged($event)"> <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> <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')">© 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>
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>
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>
Update more in the few days