<!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">
<!-- <link rel="manifest" href="manifest.json"> -->
<!-- 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://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/css/all.min.css" integrity="sha384-UHRtZLI+pbxtHCWp1t77Bi1L4ZtiqrqD80Kn4Z8NTSRyMA2Fd33n5dQ8lWUE00s/" crossorigin="anonymous"> -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.12.1/css/all.min.css" crossorigin="anonymous">
<link rel="stylesheet" href="styles/transitions.css?1592374418">
<link rel="stylesheet" href="styles/forms.css?1592866024">
<link rel="stylesheet" href="styles/style.css?1601392579">
<link rel="stylesheet" href="styles/game.css?1595615211">
<script>
function storageFactory(getStorage) {
const inMemoryStorage = {};
function isSupported() {
try {
var testKey = "__some_random_key_you_are_not_going_to_use__";
getStorage().setItem(testKey, testKey);
getStorage().removeItem(testKey);
return true;
} catch (e) {
return false;
}
}
function clear() {
if (isSupported()) {
getStorage().clear();
} else {
inMemoryStorage = {};
}
}
function getItem(name) {
if (isSupported()) {
return getStorage().getItem(name);
}
if (inMemoryStorage.hasOwnProperty(name)) {
return inMemoryStorage[name];
}
return null;
}
function key(index) {
if (isSupported()) {
return getStorage().key(index);
} else {
return Object.keys(inMemoryStorage)[index] || null;
}
}
function removeItem(name) {
if (isSupported()) {
getStorage().removeItem(name);
} else {
delete inMemoryStorage[name];
}
}
function setItem(name, value) {
if (isSupported()) {
getStorage().setItem(name, value);
} else {
inMemoryStorage[name] = String(value);
}
}
function length() {
if (isSupported()) {
return getStorage().length;
} else {
return Object.keys(inMemoryStorage).length;
}
}
return {
getItem: getItem,
setItem: setItem,
removeItem: removeItem,
clear: clear,
key: key,
get length() {
return length();
}
};
}
const localStore = storageFactory(() => localStorage);
const sessionStore = storageFactory(() => sessionStorage);
</script>
<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>
<script src="https://sdk.crazygames.com/crazygames-sdk-v1.js"></script>
<script type="text/javascript">
const crazysdk = window.CrazyGames.CrazySDK.getInstance(); //Getting the SDK
crazysdk.init(); //Initializing the SDK, call as early as possible
</script>
<!-- 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>
var aiptag = aiptag || {};
aiptag.cmd = aiptag.cmd || [];
aiptag.cmd.display = aiptag.cmd.display || [];
aiptag.cmd.player = aiptag.cmd.player || [];
var blockingAds = true;
</script>
<script async src="//api.adinplay.com/libs/aiptag/pub/SSK/shellshock.io/tag.min.js"></script>
<script>
blockingAds = false;
</script>
<!-- Google AdManager -->
<!-- include_once('./includes/header/inc_googleAdManager.php'); -->
<!-- GTM -->
<!-- Google Tag Manager -->
<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-K5MSJHJ');</script>
<!-- End Google Tag Manager -->
<script>
window.googletag = window.googletag || {cmd: []};
let inHouseSlot;
const slots = [];
const dpfNetwork = /21743024831/,
inHouseAdSlot = 'ShellShockers_LoadingScreen_HouseAds'
inHouseAdSize = [[468, 60], [970, 90], [970, 250], [728, 90]],
inHouseAdDiv = 'ShellShockers_LoadingScreen_HouseAds',
adSlots = [];
// Helper to setup slots and add to slot array
const adDefineSlot = (slot, sizes, id) => {
return adSlots.push([{slot, sizes, id}]);
};
// Defining the slots for the the array
const loadingScreeningAd = adDefineSlot(inHouseAdSlot, inHouseAdSize, inHouseAdDiv);
// Helper to add slots to google service
function addServiceToSlot() {
slots.forEach(slot => {
slot.addService(googletag.pubads());
});
}
// Get all the slots, add to google ad defineSlot method
function getAllDefinedSlots(allSlots) {
let definedSlots = [];
allSlots.forEach(adSlot => {
for (var i = 0, len = adSlot.length; i < len; i++) {
slots.push(googletag.defineSlot(dpfNetwork + adSlot[i].slot, adSlot[i].sizes, adSlot[i].id));
}
})
return addServiceToSlot(slots);
}
const gtagInHouseLoadingBannerIntialLoad = () => {
if (typeof hasPoki !== 'undefined') {
console.log('haspoki', typeof(hasPoki));
return;
}
googletag.cmd.push(function() {
getAllDefinedSlots(adSlots);
googletag.pubads().disableInitialLoad();
googletag.enableServices();
});
};
gtagInHouseLoadingBannerIntialLoad();
const adRenderedEvent = () => {
return googletag.pubads().addEventListener('slotRenderEnded', (event) => {
vueApp.disaplyAdEventObject(event);
});
};
const gtagInHouseLoadingBanner = () => {
googletag.cmd.push(function() {
googletag.pubads().refresh([slots[0]]);
adRenderedEvent();
});
};
const destroyInhouseAdForPaid = () => {
googletag.destroySlots([slots[0]]);
};
</script>
<!-- Firebase -->
<script src="https://www.gstatic.com/firebasejs/7.21.1/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/7.21.1/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/ui/4.6.1/firebase-ui-auth.js"></script>
<link type="text/css" rel="stylesheet" href="https://www.gstatic.com/firebasejs/ui/4.6.1/firebase-ui-auth.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 (let i = 0; i < query.length; i++) {
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);
var host = loc.host.split('.');
url.dom = host[0];
url.top = host[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><!-- <button id="addToHomescreen" style="z-index:333;display: none; position:absolute; top:0px; right: 75%; cursor:pointer;" class="ss_button btn_yolk bevel_yolk">Add to your desktop!</button> -->
<script>
let pwaBlockAds = false;
// if ('serviceWorker' in navigator) {
// console.log("Will the service worker register?");
// navigator.serviceWorker.register('service-worker.js')
// .then(function(reg){
// console.log("Yes, it did.");
// }).catch(function(err) {
// console.log("No it didn't. This happened:", err)
// });
// }
if (window.matchMedia('(display-mode: standalone)').matches) {
pwaBlockAds = 'utm_source' in parsedUrl.query && parsedUrl.query.utm_source === 'homescreen';
ga('send', 'event', 'pwa', 'desktop opened');
}
</script>
<audio id="theAudio" preload="metadata"></audio>
<!-- 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">
<meta name="theme-color" content="#0B93BD" />
<meta name="background-color" content="#0B93BD" />
<link rel="icon" href="favicon.ico" type="image/x-icon">
<link rel="apple-touch-icon" href="favicon192.png" sizes="192x192" />
<link rel="icon" href="favicon256.png" sizes="512x512" />
<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.30';
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;
}
const theTimeTracker = (startTime, gaVar, gaLabel) => {
const endTime = new Date();
const timerResult = endTime - startTime;
if (!Number.isInteger(timerResult) && !timerResult ) {
return;
}
return ga('send', 'timing', vueData.googleAnalytics.cat.playerStats, gaVar, timerResult, gaLabel);
};
const isShellIframe = () => window.self === window.top;
const iframeParent = () => {
const parent = (window.location != window.parent.location)
? document.referrer
: document.location.href,
domain = new URL(parent).hostname.replace(/(www.)/, '').split('.');
if (!Array.isArray(domain) && !domain.length) {
return false;
}
const index = domain.length - 2;
return {
domain: domain,
index: index,
};
};
const iframeWhitelist = (domains) => {
if (isShellIframe()) {
return;
}
const parent = iframeParent(),
domain = parent.domain,
index = parent.index;
// if in iframe and url hostname is in approved whitelist return true or false if not in list
return domains.includes(domain[index]) || domains.includes(domain[index - 1]);
};
const playShellshockers = () => {
//if not in a iframe return true
if (isShellIframe()) {
console.log('Not playing in iframe');
return true;
}
console.log('Playing in iframe');
const gamePortals = [
'poki',
'poki-gdn',
'poki.compoki',
'games.poki',
'crazygames',
'1001juegos',
'ioground',
'gogy',
'playgamesio',
'iogames',
'iogames',
'wingsiofree',
'vseigru',
'miniclip',
'red-ball4',
'speelspelletjes',
'onlinegame',
'addictinggames'
];
const parent = iframeParent(),
domain = parent.domain,
index = parent.index;
// if in iframe and url hostname is in approved whitelist return true or false if not in list
//return gamePortals.includes(domain[index]) || gamePortals.includes(domain[index - 1]);
return true; // Disabling this for now because server outages caused everyone to be blacklisted for some insane, currently unknown reason.
};
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/';
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' }];
var servicesServer = 'wss://staging.shellshock.io:8443/services/';
}
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/';
}
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);
}
function getStoredNumber (name, def) {
var num = localStore.getItem(name);
if (!num) {
return def;
}
return Number(num);
}
function getStoredBool (name, def) {
var str = localStore.getItem(name);
if (!str) {
return def;
}
return str == 'true' ? true : false;
}
function getStoredString (name, def) {
var str = localStore.getItem(name);
if (!str) {
return def;
}
return str;
}
function getStoredObject (name, def) {
var str = localStore.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 integrity="sha384-0LxWhlFxiibmXKNdwzRG0OC//XVouLJJzKBjO6dVE+A79F5W8oLjRCvg7JwzKEZP" src="src/shellshock.js?1602796947"></script>
</head>
<body>
<!-- google tag manager noscript -->
<!-- Google Tag Manager (noscript) -->
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=GTM-K5MSJHJ"
height="0" width="0" style="display:none;visibility:hidden"></iframe></noscript>
<!-- End Google Tag Manager (noscript) --> <!-- Ads -->
<div id="gameAdContainer" class="hideme">
<!-- <div id="multisizeBannerAdPlaceholder"></div>
<div id="shellshock-io_multisize"></div> -->
<!-- AdInPlay tag ID -->
<!-- ShellShock_Respawn_Banner -->
<!-- <div id='div-gpt-ad-ShellShock_Respawn_Banner'>
<script type='text/javascript'>
googletag.cmd.push(function() { googletag.display('div-gpt-ad-ShellShock_Respawn_Banner'); });
</script>
</div> -->
</div>
<div id="shellshockers_titlescreen">
</div>
<div id="shellshockers_chicken_nugget_banner">
</div>
<div id="shellshockers_respawn_banner">
</div>
<div id="ShellShockers_LoadingScreen_HouseAds">
<script type='text/javascript'>
googletag.cmd.push(function() { googletag.display('ShellShockers_LoadingScreen_HouseAds') });
</script>
</div>
<div id="videoAdContainer">
<div id="preroll"></div>
</div>
<!-- <div class="video_ad_wrapper">
<video id="asc_video_ad" class="video-js vjs-default-skin" controls preload="auto" width="640" height="360" muted="true" style="display: none;">
<source src="video/tiny.mp4" type="video/mp4" />
</video>
</div> -->
<div id="ss_background"></div>
<!-- Instantiate the Vue instance -->
<div id="app" :class="[currentLanguageCode, classObject]"> <!-- vue instance div: all vue-controlled elements MUST be inside this tag -->
<!-- <asc-video-player id="mainVideoPlayer" ref="mainVideoPlayer" adTagUrl="adTagUrl"></asc-video-player> -->
<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" :is-from-eu="showPrivacyOptions" :controller-id="controllerId" :controller-type="controllerType"></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: Egg Store single -->
<large-popup id="popupEggStoreSingle" ref="popupEggStoreSingle" stop-key-capture="true" @popup-closed="onSharedPopupClosed" :overlay-close="false" class="popup-store-single">
<template slot="content">
<egg-store-item v-for="item in eggStoreItems" :key="item.sku" :item="item" :loc="loc" :account-set="accountSettled" v-if="eggStorePopupSku && item.sku === eggStorePopupSku"></egg-store-item>
</template>
</large-popup>
<!-- Popup: Unsupported Platform -->
<large-popup id="unsupportedPlatformPopup" ref="unsupportedPlatformPopup" hide-close="true">
<template slot="content">
<h2>{{ loc['unsupported_platform'] }}</h2>
<div>{{ loc[unsupportedPlatformPopup.contentLocKey] }}</div>
</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.30</strong><ul>
<li>Added the BADOOSH Scrambler to the Egg Shack!
<li>Removed the Demon Wings from the Egg Shack
</ul><hr class='blue'><strong>0.29</strong><ul>
<li>Tweaked vertices wizardry means an average of 5 FPS eggstra!
<li>Added the Limited Edition Demon Wings to the Egg Shack!
<li>Added the Halloween skin series for this month only
<li>Launched the Stampede! event with over 20 stamps added
<li>Vaulted the Chicken skin series
<li>Added new map Haunted directly to the public map pool
<li>Moved Jailbreak to the private map pool
</ul><hr class='blue'><strong>0.28.6</strong><ul>
<li>Updates to new map lighting and shaders
</ul><hr class='blue'><strong>0.28.5</strong><ul>
<li>New Lighting System Implemented! Better colours / Better Shadows
<li>Improved unseen verticies - You may notice an FPS increase!
<li>Fixed some issues with simultanious code redemtion.
<li>Included new <a target='_blank' title='Get the Friday the 13th puzzle game here.' href='http://www.f13killerpuzzle.com/xboxone'>Friday the 13th: Killer Puzzle</a> Stamp
</ul><hr class='blue'><strong>0.28.4</strong><ul>
<li>New Premium item added - The Epic Rooster Wings!
<li>Pop-pop Premium item vaulted
<li>Spawn points on Stage improved
<li>Added the Chicken Skin series for this month only
<li>Vaulted the Gallegsy skin series
<li>Added new map Blender to the private map pool
<li>Moved Feedlot and Road to the public map pool
<li>Moved Stage and Blue to the private map pool
</ul><hr class='blue'><strong>0.28.3</strong><ul>
<li>New Premium item added - Pop-Pop 9mm. POP!
<li>Gallegsy Wings Premium item vaulted
<li>Mud Gulch subtley improved. Can you find it?
</ul><hr class='blue'><strong>0.28.2</strong><ul>
<li>New audio engine that will actually work on your terrible laptop!
<li>Added an Eggsclusive hat to the Egg Shack!
<li>Added the Galleggsy Skin series for this month only
<li>Vaulted the Rockstar Skin series
<li>Added new map Four Quarters to the private map pool
<li>Edits made to Bastion to improve player flow
<li>Moved Two Towers and Stage to the public map pool
<li>Moved Dirt and Road to the private map pool
</ul><hr class='blue'><strong>0.28.1</strong><ul>
<li>Added KILLSTREAKS! Get 5 Kills to earn the Hardboiled armor powerup! Get 10 kills to earn the Eggbreaker damage multiplier!
<li>Added NEW PREMIUM ITEMS! Check the Store for 8 new ultra-rare hats and skins!
</ul><hr class='blue'><strong>0.27.82</strong><ul>
<li>Poki stuff
</ul><hr class='blue'><strong>0.27.81</strong><ul>
<li>Added an Eggslusive weapon to the Egg Shack!
<li>Can you feel the music? New Droppin' Mad Beaks event
<li>Added the Rockstar Skin series for this month only
<li>Added Map Stage to the private map pool
<li>Updated Map Space Factory - now even rampierer
<li>Moved Castle and Space Factory to the public map pool
<li>Moved Two Towers and Feedlot to the private map pool
</ul><hr class='blue'><strong>0.27.8</strong><ul>
<li>Added an Eggslusive weapon to the Egg Shack!
<li>Can you feel the music? New Droppin' Mad Beaks event
<li>Added the Rockstar Skin series for this month only
<li>Added Map Stage to the private map pool
<li>Updated Map Space Factory - now even rampierer
<li>Moved Castle and Space Factory to the public map pool
<li>Moved Two Towers and Feedlot to the private map pool
</ul><hr class='blue'><strong>0.27.7</strong><ul>
<li>Add new egg store sale notification
</ul><hr class='blue'><strong>0.27.6</strong><ul>
<li>Add new popup for sale items
</ul><hr class='blue'><strong>0.27.5</strong><ul>
<li>Added the Rotten Skin series for this month only
<li>Added Map Temple to the private map pool
<li>Added the Scorched Horizon Mask to the shop
<li>Moved Fort Flip and Moonbase to the public map pool
<li>Moved Castle and Palace Siege to the private map pool
</ul><hr class='blue'><strong>0.27.4</strong><ul>
<li>New setting: Safe Names - Randomizes all player names
</ul><hr class='blue'><strong>0.27.3</strong><ul>
<li>Added the Amazing Raid.Land Skins
<li>Added Bastion Map to the private Map Pool
<li>Fixed Ladder Glitches on Jailbreak
<li>Vaulted Easter Items
<li>Moved Moonbase to the private map pool
<li>Moved Skyscratcher to the public map pool!
</ul><hr class='blue'><strong>0.27.2</strong><ul>
<li>The Blue Wizards have escaped!
<li>EGG ORG is gone... for now. It will take time to return things to normal
<li>STAY INSIDE - Edited Map Biohazard to remove bugs
<li>New map Jailbreak added to Private games
<li>Vaulted Evil EGG ORG Stamp
</ul><hr class='blue'><strong>0.27.1</strong><ul>
<li>All Hail our Glorious Corporate Overlords, EGG ORG! - stamp now in store.
<li>STAY INSIDE - Added Map Biohazard to the private map pool
<li>WASH HANDS - Added Face Masks to the store
<li>Vaulted Saint Patricks Day skins
<li>Added Easter skins and cosmetics
</ul><hr class='blue'><strong>0.27.0</strong><ul>
<li>Added Gamepad Support! You can now find extra options in the setting menu
<li>A whole host of bug fixes!
<li>Fixes to Castle Map
</ul><hr class='blue'><strong>0.26.4</strong><ul>
<li>Added Quick-Switch weapon select on respawn menu - Noice
<li>Your favorite Chicken Nugget has had a makeover
<li>Added Map 'Sky Scratcher' to the private map pool
<li>Vaulted Valentine's Day Skins
<li>Added Saint Patrick's Day skins - Too Ra Loo!
<li>Updated 'Space Factory' map with better bullet collision
<li>Minor 'Road' map updates
</ul><hr class='blue'><strong>0.26.3</strong><ul>
<li>Every weekend in February is a DOUBLE XP weekend!
<li>Changes to Mud Gulch and Space Arena, now at least 1.4 times as fun
<li>Moved Fort Flip to Private and Mud Gulch to public
<li>Added Map Space Factory to the private map pool
<li>Added Hyper Eggspensive Egg in Black skins
<li>Added Valentines Skins for the month of February
<li>Added enhanced 2X Egg functionality and UI elements
<li>New Years Eve skins have been vaulted
<li> Extra Language support added for non-English Players
</ul><hr class='blue'><strong>0.26.2</strong><ul>
<li>Christmas and Eggwalker skins have been vaulted
<li>New Years and Nuke Zone skins have been added to the store
<li>New map Mud Gulch added to the private map pool
<li>Cluckgrounds updated AND moved to the Public Map Pool
<li>By popular demand, Ruins has been added back to the Public Map Pool
</ul><hr class='blue'><strong>0.26.1</strong><ul>
<li>New functionallity added for Double Egg Weekend
<li>Get Yolked this weekend with DOUBLE THE EGGS (Golden Nugget = 4X eggs this weekend)
<li>Map Cluckgrounds updated with a more open downstairs
</ul><hr class='blue'><strong>0.26.0</strong><ul>
<li>Christmas and Eggwalker skins are available in the store
<li>New map Cluckgrounds added to the private map pool
<li>Palace Siege moved to the Public Map Pool
<li>Enhanced backend bugfixes
<li>Return of the nugget
</ul><hr class='blue'><strong>0.25.7</strong><ul>
<li>A host of more unexciting bug fixes and security patches.
<li>Improved SEO functions on the main page and other things you probably don't care about. Read it now by scrolling down... umm... after the changelog is closed.
</ul><hr class='blue'><strong>0.25.6</strong><ul>
<li>A host of unexciting bug fixes and security patches.
<li>The Chicken Nugget is back from holiday and once again, doubling eggs for an hour
</ul><hr class='blue'><strong>0.25.5</strong><ul>
<li>New default weapons - look better, sound better, plays the same!
<li>Vaulted the Guy Fawkes Mask
<li>Small map balance tweaks to Moon Arena and Road
<li>Spatula added to Palace Seige
<li>General Bug Fixes
</ul><hr class='blue'><strong>0.25.4</strong><ul>
<li>Happy Thanksgiving! Enjoy some turkey with your eggs with a bunch of festive skins.
<li>Vaulted the Halloween items.
<li>Added Map: Dual Pyramid to the private map pool.
<li>Added Map: Palace Siege to the private map pool.
<li>Road has been moved to a public map, look for it in the regular rotation.
<li>Ruins has been moved to a private only map.
</ul><hr class='blue'><strong>0.25.3</strong>
<ul>
<li>Some refinements to the new collision detection to prevent some strange things that you probably thought where fun. TOO BAD.
<li>Patched up a few holes in the maps, because some of those were fun, too.
</ul>
<hr class='blue'><strong>0.25.2</strong>
<ul>
<li>Halloween items are back for you and your BOO... Sorry.
<li>FIX grenades sometimes flying off in random directions.
<li>FIX cases where weapons would occasionally become completely ineffective.
<li>FIX certain instances where some shots would fail to register.
</ul>
<hr class='blue'><strong>0.25.1</strong>
<ul>
<li>Updates to the 1v1 Metadata
<li>Make the Egg Clickable on the Title Screen
<li>General minor bug fixes and Optimizations
</ul>
<hr class='blue'><strong>0.24.1</strong>
<ul>
<li>Updates to the new 1v1 Maps -- more hidey hidey.
<li>Fixed a bug where redeeming a code currently does not populate in inventory until you refresh.
<li>Fixed a bug where people's names were getting capitalized on the Kill/Death message.
<li>Added a sign in button to anonymouse warning popup.
</ul>
<hr class='blue'><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-close="true" :overlay-close="false" @popup-cancel="anonWarningPopupCancel" @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="cancel">{{ loc.account_anon_warn_confirm }}</template>
<template slot="confirm">{{ loc.sign_in }}</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>
<!-- 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>
<small-popup ref="adBlockerPopup" id="adBlockerPopup" :overlay-close="false" hide-confirm="true" hide-cancel="true" hide-close="true">
<template slot="header">
We've detected ad blocker!
</template>
<template slot="content">
<p>To <i>avoid</i> this message please turn <i>off</i> ad blocker.</p>
<h4>Please wait</h4>
<h3>{{adBlockerCountDown}}</h3>
</template>
</small-popup>
<!-- Popup: PWA -->
<small-popup id="pwaPopup" class="pwa-popup" ref="pwaPopup" hide-confirm="true" @popup-closed="onSharedPopupClosed">
<!-- <template slot="header">{{ loc.p_settings_privacy }}</template> -->
<template slot="content">
<p>{{loc.pwa_desc_one}}</p>
<p>{{loc.pwa_desc_two}}</p>
<button @click="pwaBtnClick" class="ss_button btn_big btn_green bevel_green btn_height_auto btn-pwa-download">
<div class="pwa-btn-img-box roundme_lg bg-darkgreen">
<img src="favicon192.png" alt="Egg yolk">
<i class="fas fa-share" aria-hidden="true"></i>
</div>
{{loc.pwa_btn_line_one}}<br/>{{loc.pwa_btn_line_two}}
</button>
</template>
<template slot="cancel">{{loc.pwa_no_thanks}}</template>
</small-popup>
</div> <!-- End of vue instance div -->
<script>
var vueApp;
var vueData = {
ready: false,
accountSettled: false,
missingFeatures: [],
changelogVersion: version,
firebaseId: null,
photoUrl: null,
maskedEmail: null,
isEmailVerified: false,
isAnonymous: true,
showPrivacyOptions: isFromEU,
isOfAge: false,
showTargetedAds: false,
delayTheCracking: false,
displayAdFunction: Function,
titleScreenDisplayAd: Function,
displayAdObject: false,
isPoki: false,
isPokiGameLoad: false,
pokiRewardReady: false,
isPokiNewRewardTimer: false,
videoRewardTimers: {
initial: 300000,
primary: 420000
},
pokiRewNum: 1,
adUnits: {
display: {
respawn: 'shellshockers_respawn_banner',
home: 'shellshockers_titlescreen',
nugget: 'shellshockers_chicken_nugget_banner',
house: 'ShellShockers_LoadingScreen_HouseAds'
}
},
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,
getMusicVolume: 0.5,
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: [],
settingsUi: {
adjusters: {
misc: [
{ id: 'volume', locKey: 'p_settings_mastervol', min: 0, max: 1, step: 0.01, value: 1, multiplier: 100 }
],
mouse: [
{ id: 'mouseSpeed', locKey: 'p_settings_mousespeed', min: 1, max: 100, step: 1, value: 30 }
],
gamepad: [
{ id: 'sensitivity', locKey: 'p_settings_sensitivity', min: 1, max: 100, step: 1, value: 30 },
{ id: 'deadzone', locKey: 'p_settings_deadzone', min: 0, max: 1, step: 0.01, value: 0.3, precision: 2 }
],
music: [
{ id: 'musicVolume', locKey: 'p_settings_music_volume', min: 0, max: 1, step: 0.01, value: 0.5, multiplier: 100 }
],
},
togglers: {
misc: [
{ id: 'holdToAim', locKey: 'p_settings_holdtoaim', value: true },
{ id: 'enableChat', locKey: 'p_settings_enablechat', value: true },
{ id: 'safeNames', locKey: 'p_settings_safenames', 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 },
{ id: 'musicStatus', locKey: 'p_settings_music', value: true }
],
mouse: [
{ id: 'mouseInvert', locKey: 'p_settings_invertmouse', value: false },
],
gamepad: [
{ id: 'controllerInvert', locKey: 'p_settings_invertcontroller', value: false },
]
},
controls: {
keyboard: {
// The ids map to the field names in settings.controls[category]
game: [
{ id: 'up', side: 'left', locKey: 'keybindings_forward', value: 'W' },
{ id: 'down', side: 'left', locKey: 'keybindings_backward', value: 'S' },
{ id: 'left', side: 'left', locKey: 'keybindings_left', value: 'A' },
{ id: 'right', side: 'left', locKey: 'keybindings_right', value: 'D' },
{ id: 'jump', side: 'left', locKey: 'keybindings_jump', value: 'SPACE' },
{ id: 'fire', side: 'right', locKey: 'keybindings_fire', value: 'MOUSE 0' },
{ id: 'scope', side: 'right', locKey: 'keybindings_aim', value: 'SHIFT' },
{ id: 'reload', side: 'right', locKey: 'keybindings_reload', value: 'R' },
{ id: 'swap_weapon', side: 'right', locKey: 'keybindings_swapweapon', value: 'E' },
{ id: 'grenade', side: 'right', locKey: 'keybindings_grenade', value: 'Q' }
],
spectate: [
{ id: 'ascend', locKey: 'keybindings_spectate_ascend', value: 'E' },
{ id: 'descend', locKey: 'keybindings_spectate_descend', value: 'C' }
]
},
gamepad: {
// The ids map to the field names in settings.gamepad[category]
game: [
{ id: 'jump', locKey: 'keybindings_jump', value: '0' },
{ id: 'fire', locKey: 'keybindings_fire', value: '1' },
{ id: 'scope', locKey: 'keybindings_aim', value: '2' },
{ id: 'reload', locKey: 'keybindings_reload', value: '3' },
{ id: 'swap_weapon', locKey: 'keybindings_swapweapon', value: '4' },
{ id: 'grenade', locKey: 'keybindings_grenade', value: '5' }
],
spectate: [
{ id: 'ascend', locKey: 'keybindings_spectate_ascend', value: '1' },
{ id: 'descend', locKey: 'keybindings_spectate_descend', value: '2' }
]
}
}
},
songChanged: false,
music: {
isMusic: false,
musicJson: 'sponsors.json',
musicSrc: '',
theAudio: '',
playing: false,
sponsors: {},
sponsor: '',
currIndex: 0,
currentTime: 0,
duration: 0,
timer: null,
progress: 0,
volume: 10,
hideClass: 'music-widget--fade-out',
serverTracks: {
id: '',
title: '',
artist: '',
album: '',
albumArt: '',
url: '',
trackUrltest: 'https://shellshock.io',
sponsor: '',
sponsorUrl: '',
}
},
home: {
joinPrivateGamePopup: {
code: '',
showInvalidCodeMsg: false,
validate: function () {
if (this.code.length == 0) {
console.log('failed validation');
this.showInvalidCodeMsg = true;
BAWK.play('ui_reset');
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;
BAWK.play('ui_reset');
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',
}
},
isPaused: true,
isEvent: false,
doubleEggWeekendSoon: false,
doubleEggWeekend: false,
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'
},
unsupportedPlatformPopup: {
titleLocKey: 'unsupported_platform',
contentLocKey: ''
},
windowDimensions: {
width: 0,
height: 0,
},
bannerAds: {
bannerElId: '',
},
googleAnalytics: {
isUser: null,
cat: {
purchases: 'Purchases',
purchaseComplete: 'Purchase Complete',
itemShop: 'Item Shop',
inventory: 'Inventory',
playerStats: 'player stats',
play: 'play game',
redeem: 'Redeem'
},
action : {
eggShackClick: 'Egg Shack Click',
eggShackProductClick: 'Egg Shack Product Click',
purchaseComplete: 'Purchase Complete',
goldenChickenProductClick: 'Golden Chicken Product Click',
goldenChickenNuggetClick: 'Golden Chicken Nugget Click',
shopClick: 'Shop Opened ',
shopItemClick: 'Shop Item Selected',
shopItemPopupClick: 'Shop Item Popup Click',
shopItemPopupBuy: 'Item purchased',
shopItemNeedMoreEggsPopup: 'Need More Eggs Popup',
inventorySelected: 'Inventory Item ',
eggCount: 'Egg Count',
inventoryTabClick: 'Inventory Opened',
playGameClick: 'Play Game Click',
redeemed: 'Redeemed',
redeemClick: 'Redeem open',
languageSwitch: 'Language setting change',
langBeforeUpdate: 'Language before auto detect',
privateGame: 'Private Game',
shareGamePopup: 'Share game Popup',
shareGameCopy: 'Shared game code',
createGame: 'Created game',
joinGame: 'Joined game',
playerLimit: 'Player limit',
timesPlayed: 'Times played',
anonymousPopupOpenAuto: 'Anon warning auto opened',
anonymousPopupOpen: 'Anon warning opened',
anonymousPopupSignupClick: 'Anon warning Sign in clicked',
anonymousPopupAgreeClick: 'Anon warning Understood clicked',
denyAnonUserPopup: 'Deny anon user popup',
denyAnonUserPopupSignin: 'sign in click',
faqPopupClick: 'FAQ popup open',
switchTeams: 'Switched Teams',
error: 'error',
signIn: 'Sign in'
},
label : {
signInClick: 'sign in click',
understood: 'Understood click',
getMoreEggs: 'Get More Eggs Click',
waitForGameReadyTimeout: 'waitForGameReady timeout',
signInAuthFailed: 'authorization failed',
signInTiming: 'Sign in delay',
signInCompleted: 'Completed',
signInOut: 'Signed out',
signInFailed: '',
homeToGameLoading: 'Home to game loading',
loading: 'Loading'
}
},
urlParams: null,
urlParamSet: null,
adTagUrl: 'https://pubads.g.doubleclick.net/gampad/ads?iu=/21743024831/ShellShock_Video&description_url=__page-url__&env=vp&impl=s&correlator=&tfcd=0&npa=0&gdfp_req=1&output=vast&sz=640x480&unviewed_position_start=1',
eggStoreItems: [
{sku: 'egg_pack_small', price: 5, salePrice: '', title: 'p_egg_shop_eggpile', desc: 'p_egg_shop_eggpile_desc', flagText: '', img: './img/eggshop_egg1.png', discount: '', itemId: '', type: 'eggs', inStore: false},
{sku: 'gun_gauge_techno', price: 10, salePrice: '', title: 'p_item_shop_premium_title', desc: 'p_item_shop_premium_desc', flagText: 'p_item_shop_premium_label', img: './img/store/items/shack-gun-techno-dozen-gauge.gif', discount: '', itemId: {id: 3627}, type: 'item', inStore: true},
{sku: 'egg_pack_medium', price: 10, salePrice: '', title: 'p_egg_shop_eggbasket', desc: 'p_egg_shop_eggbasket_desc', flagText: 'p_egg_shop_mostpopular', img: './img/eggshop_egg2.png', discount: '', itemId: '', type: 'eggs', inStore: true},
{sku: 'egg_pack_large', price: 20, salePrice: '', title: 'p_egg_shop_eggbox', desc: 'p_egg_shop_eggbox_desc', flagText: '', img: './img/eggshop_egg3.png', discount: '', itemId: '', type: 'eggs', inStore: true},
{sku: 'item_hat_yolk_arms', price: 5, salePrice: '', title: 'p_item_shop_title_hat_yolk_arms', desc: 'p_item_shop_desc_hat_yolk_arms', flagText: 'p_item_shop_premium_label', img: './img/store/items/shack-hat-yolk-arms.gif', discount: '', itemId: {id: 1112}, type: 'item', inStore: false},
{sku: 'item_hat_cape', price: 5, salePrice: '', title: 'p_item_shop_title_hat_magic_cape', desc: 'p_item_shop_desc_hat_magic_cape', flagText: 'p_item_shop_premium_label', img: './img/store/items/shack-hat-cape.gif', discount: '', itemId: {id: 1105}, type: 'item', inStore: false},
{sku: 'item_hat_dragon', price: 10, salePrice: '', title: 'p_item_shop_title_hat_dragon', desc: 'p_item_shop_desc_hat_dragon', flagText: 'p_item_shop_premium_label', img: './img/store/items/shack-hat-dragon.gif', discount: '', itemId: {id: 1092}, type: 'item', inStore: false},
{sku: 'item_hat_space_gladi', price: 10, salePrice: '', title: 'p_item_shop_title_hat_gladiator', desc: 'p_item_shop_desc_hat_gladiator', flagText: 'p_item_shop_premium_label', img: './img/store/items/shack-hat-gladiator.gif', discount: '', itemId: {id: 1110}, type: 'item', inStore: false},
{sku: 'item_hat_zombie_mask', price: 15, salePrice: '', title: 'p_item_shop_title_hat_zombie_mask', desc: 'p_item_shop_desc_hat_zombie_mask', flagText: 'p_item_shop_premium_label', img: './img/store/items/shack-hat-zombie-mask.gif', discount: '', itemId: {id: 1126}, type: 'item', inStore: false},
{sku: 'item_gun_9mm_space', price: 15, salePrice: '', title: 'p_item_shop_title_gun_cluck9mm_space', desc: 'p_item_shop_desc_gun_cluck9mm_space', flagText: 'p_item_shop_premium_label', img: './img/store/items/shack-gun-cluck9mm-space.gif', discount: '', itemId: {id: 3016}, type: 'item', inStore: false},
{sku: 'item_hat_oni', price: 20, salePrice: '', title: 'p_item_shop_title_hat_oni', desc: 'p_item_shop_desc_hat_oni', flagText: 'p_item_shop_premium_label', img: './img/store/items/shack-hat-oni.gif', discount: '', itemId: {id: 1125}, type: 'item', inStore: false},
{sku: 'item_gun_csg1_space', price: 20, salePrice: '', title: 'p_item_shop_title_gun_csg1_space', desc: 'p_item_shop_desc_gun_csg1_space', flagText: 'p_item_shop_premium_label', img: './img/store/items/shack-gun-csg1-space.gif', discount: '', itemId: {id: 3416}, type: 'item', inStore: false},
{sku: 'egg_pack_giant', price: 50, salePrice: 50/2, title: 'p_egg_shop_eggcluckton', desc: 'p_egg_shop_eggcluckton_desc', flagText: 'p_egg_shop_sale', img: './img/eggshop_egg4.png', discount: '50%', itemId: '', type: 'eggs', inStore: true},
{sku: 'golden_chicken_pass', price: 4.99, salePrice: '', title: '', desc: '', flagText: '', img: '', discount: '', itemId: '', type: 'eggs', inStore: false},
],
eggStoreReferral: '',
eggStoreHasSale: false,
eggStorePopupSku: 'egg_pack_small',
showNugget: true,
isMiniGameComplete: false,
showGoldenChicken: false,
nugStart: null,
nugCounter: null,
isBuyNugget: false,
adBlockerCountDown: 10,
controllerType: 'generic',
controllerId: '',
controllerButtonIcons: {
xbox: [
'A',
'B',
'X',
'Y',
'LB',
'RB',
'LT',
'RT',
'Select',
'Start',
'<img class="ss_buttonbind_icon" src="img/controller/button_stickleft.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_stickright.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_dpadup.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_dpaddown.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_dpadleft.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_dpadright.svg">'
],
ps: [
'<img class="ss_buttonbind_icon" src="img/controller/button_cross.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_circle.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_square.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_triangle.svg">',
'LB',
'RB',
'LT',
'RT',
'Select',
'Start',
'<img class="ss_buttonbind_icon" src="img/controller/button_stickleft.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_stickright.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_dpadup.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_dpaddown.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_dpadleft.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_dpadright.svg">'
],
switchpro: [
'B',
'A',
'Y',
'X',
'LB',
'RB',
'LT',
'RT',
'-',
'+',
'<img class="ss_buttonbind_icon" src="img/controller/button_stickleft.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_stickright.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_dpadup.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_dpaddown.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_dpadleft.svg">',
'<img class="ss_buttonbind_icon" src="img/controller/button_dpadright.svg">'
],
generic: [
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'10',
'11',
'12',
'13',
'14',
'15'
]
},
pwaDeferEvent: ''
}</script>
<!-- Shared tags must come before the screen tags -->
<script id="events-template" type="text/x-template">
<div v-if="(doubleEggWeekendSoon || doubleEggWeekend) && showUi" id="event-notifications">
<div class="double-eggs">
<img v-if="doubleEggWeekendSoon && !doubleEggWeekend" src="/img/events/shellshockers_doubleEgg01.png" alt="Double Egg weekend coming soon">
<img v-if="doubleEggWeekend" src="/img/events/shellshockers_doubleEgg02.png" alt="Double Egg weekend now happening">
</div>
</div>
</script>
<script>
const comp_events = {
template: '#events-template',
props: ['show', 'owOn', 'showSoon', 'showUi'],
created() {
this.checkForEvents();
},
data: function () {
return vueData;
},
methods: {
isEventDate(days) {
const day = new Date().getUTCDay();
return days.includes(day);
},
doubbleEggSoon() {
return this.doubleEggWeekendSoon = this.isEventDate([4,5]);
},
doubleEggOn() {
const ISEVENT = this.isEventDate([5,6,0]);
if (!ISEVENT) {
return;
}
const DATE = new Date();
let day = DATE.getUTCDay();
if (day === 5) {
let time = DATE.getUTCHours();
if (time >= 19) {
return (
this.doubleEggWeekend = ISEVENT,
this.isEvent = ISEVENT
)
} else {
return (
this.doubleEggWeekend = false,
this.isEvent = false
)
}
} else {
return (
this.doubleEggWeekend = ISEVENT,
this.isEvent = ISEVENT
)
}
},
checkEvents() {
return (
this.doubbleEggSoon(),
this.doubleEggOn()
)
},
checkForEvents() {
this.checkEvents();
if (!this.doubleEggWeekend && this.isEventDate([4,5,6,0])) {
setTimeout(() => {
return this.checkForEvents();
}, 60000);
}
return;
},
},
};
</script><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>
<wobbly-egg></wobbly-egg>
<p class="load_message">{{ footer }}</p>
<display-ad id="div-gpt-ad-shellshockers-loading-houseads-wrap" ref="loadingScreenDisplayAd" :houseAd="true" adUnit="ShellShockers_LoadingScreen_HouseAds" pokiAdSize="728x90" :override="true"></display-ad>
</div>
</transition>
</script>
<script id="wobble-egg-template" type="text/x-template">
<div id="wobbly-egg">
<svg viewBox="0 0 240 240" :class="[loadEggcontainer, {noanimate: noAnimate}]" 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" :class="{noanimate: noAnimate}" 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="[loadEggwhite, {noanimate: noAnimate}]" 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="[loadEggyolk, {noanimate: noAnimate}]" ry="38" rx="38" id="svg_eggyolk" cy="120" cx="120" stroke-width="0" fill="url(#load_yolkgradient)"/>
</g>
</svg>
</div>
</script>
<script>
var comp_wobbly_egg = {
template: '#wobble-egg-template',
props: ['noAnimate'],
data: function () {
return {
loadEggyolk: 'load_eggyolk',
loadEggwhite: 'load_eggwhite',
loadEggcontainer: 'load_eggcontainer'
}
}
};
</script>
<script>
var comp_spinner_overlay = {
template: '#spinner-overlay-template',
components: {
'wobbly-egg': comp_wobbly_egg
},
props: ['loc'],
data: function () {
return {
isShowing: false,
header: '',
footer: '',
adIsShowing: false,
}
},
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['ui_game_loading'];
this.header = this.loc['building_map'];
this.footer = '{0}... {1}%'.format(msg, percent);
this.isShowing = true;
},
hide: function () {
this.isShowing = false;
this.$emit('close-display-ad');
},
hideDisplayAd() {
this.adIsShowing = false;
console.log('do it');
},
showDisplayAd() {
this.adIsShowing = true;
},
toggleDisplayAd() {
return this.adIsShowing = this.adIsShowing ? false : true;
}
},
};
</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);
}
if (!this.isShowing) {
console.log('Closed: ' + this.popupId);
this.$emit('popup-closed');
vueApp.gameUiRemoveClassForNoScroll();
this.cancelEventOverLayClickEscapeClose();
} else {
console.log('Opened: ' + this.popupId);
this.$emit('popup-opened');
vueApp.scrollToTop();
vueApp.gameUiAddClassForNoScroll();
this.outsideClickClose();
}
if (!extern.inGame) {
vueApp.toggleTitleScreenAd();
}
},
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();
BAWK.play('ui_popupclose');
},
onXClick: function () {
this.$emit('popup-x');
this.close();
BAWK.play('ui_popupclose');
},
cancelClick: function () {
this.close();
this.$emit('popup-cancel');
BAWK.play('ui_popupclose');
},
confirmClick: function () {
if (this.popupModel && this.popupModel.validate && !this.popupModel.validate()) {
return;
}
this.close();
this.$emit('popup-confirm');
BAWK.play('ui_playconfirm');
},
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="display-ad-template" type="text/x-template">
<transition name="fade">
<div v-show="isAdShowing" :id="id" class="display-ad-container" :class="theClass"></div>
</transition>
</script>
<script>
// Register popup components globally
Vue.component('display-ad', createDisplayAdComponent('#display-ad-template'));
function createDisplayAdComponent(templateId) {
return {
template: templateId,
props: {
id: String,
adUnit: String,
isHidden: Boolean,
poki: Boolean,
pokiAdSize: String,
override: Boolean,
houseAd: Boolean
},
data: function () {
return {
isAdShowing: false,
hideAds: false,
theAd: ''
}
},
mounted() {
this.$nextTick(() => {
this.theAd = document.getElementById(this.adUnit);
this.getTheAd();
});
this.override = this.override || false;
},
methods: {
getTheAd() {
if (vueData.isPoki || extern.adsblocked) {
return;
}
this.$el.appendChild(this.theAd);
},
setVisible(visible) {
if (extern.account.hideAds) {
console.log('Product hides ads');
this.isAdShowing = false;
return;
}
if (extern.adsblocked) {
console.log('Closure hides ads');
this.isAdShowing = false;
return;
};
this.isAdShowing = visible;
if (!this.isAdShowing) {
window.removeEventListener('resize', this.hideAdBasedOnscreenSize);
if (vueApp.isPoki && this.pokiAdSize) PokiSDK.destroyAd(this.adWrapper);
return;
} else {
this.triggerAd();
setTimeout(() => this.hideAdBasedOnscreenSize(), 500);
window.addEventListener('resize', this.hideAdBasedOnscreenSize);
return;
}
},
show() {
console.log(`display ad ${this.id} showing`);
this.setVisible(true);
},
hide() {
this.setVisible(false);
console.log(`display ad ${this.id} hiding`);
},
triggerAd() {
if (!vueApp.isPoki) {
if (this.houseAd) {
gtagInHouseLoadingBanner();
return;
}
aiptag.cmd.display.push(() => aipDisplayTag.display(this.adUnit));
return;
} else {
if (this.pokiAdSize) {
PokiSDK.displayAd(this.$el, this.pokiAdSize);
ga('send', 'event', 'Poki', 'Display ad', this.$el.id)
}
return;
}
},
toggleAd() {
if (extern.adsblocked) {
this.isAdShowing = false;
return;
};
this.$nextTick(() => {
if (this.isAdShowing) {
return this.isAdShowing = false;
}
return this.isAdShowing = true;
});
},
hideAdBasedOnscreenSize() {
let adWidth = this.$el.offsetWidth;
let intViewportWidth = window.innerWidth;
if (vueApp.displayAdObject && vueApp.displayAdObject > 1 ) {
if (vueApp.displayAdObject < 970) {
return;
}
if (vueApp.displayAdObject > intViewportWidth ) {
this.hide();
}
} else {
if (adWidth < 970) {
return;
}
if (adWidth > intViewportWidth ) {
this.hide();
}
}
},
},
computed: {
theClass() {
return this.adUnit.toLowerCase().replace(/_/g, "-");
}
},
watch: {
isHidden(value) {
if (!value) {
this.hide()
}
},
}
}
}
</script>
<!-- include_once('./includes/shared_tags/inc_tag_asc_video_player.php'); -->
<script id="language-selector-template" type="text/x-template">
<select id="pickLanguage" v-model="languageCode" @click="BAWK.play('ui_click')" @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) {
BAWK.play(sound);
},
onChangeLanguage: function () {
vueApp.changeLanguage(this.languageCode);
// Update localStore for selected language.
localStore.setItem('languageSelected', this.languageCode);
BAWK.play('ui_onchange');
ga('send', 'event', {
eventCategory: vueData.googleAnalytics.cat.playerStats,
eventAction: vueApp.googleAnalytics.action.languageSwitch,
eventLabel: this.languageCode,
});
}
},
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;
BAWK.play('ui_playconfirm');
},
onAgreeClicked: function () {
this.showingConsent = true;
this.showingNotification = false;
extern.doConsent();
BAWK.play('ui_onchange');
},
onDisagreeClicked: function () {
this.showingNoConsent = true;
this.showingNotification = false;
extern.doNotConsent();
BAWK.play('ui_onchange');
}
}
};
</script>
<script id="settings-template" type="text/x-template">
<div>
<h1 class="roundme_sm">{{ loc.p_settings_title }}</h1>
<div id="horizontalTabs">
<button id="keyboard_button" @click="selectTab" class="ss_bigtab bevel_blue ss_marginright" :class="(showKeyboardTab ? 'selected' : '')"><img src="img/ico_keyboard.svg" class="ss_bigtab_icon"> <img src="img/ico_mouse.svg" class="ss_bigtab_icon"></button>
<button id="controller_button" @click="selectTab" class="ss_bigtab bevel_blue ss_marginright" :class="(showControllerTab ? 'selected' : '')"><img src="img/ico_gamepad.svg" class="ss_bigtab_icon"></button>
<button id="misc_button" @click="selectTab" class="ss_bigtab bevel_blue" :class="(showMiscTab ? 'selected' : '')"><img src="img/ico_monitor.svg" class="ss_bigtab_icon"> <img src="img/ico_speaker.svg" class="ss_bigtab_icon"> <img src="img/ico_privacy.svg" class="ss_bigtab_icon"></button>
</div>
<div id="popupInnards" class="roundme_sm fullwidth f_col ss_margintop_sm ss_marginbottom_xl">
<div id="settings_keyboard" v-show="showKeyboardTab">
<h3 class="nospace">{{ loc.p_settings_keybindings }}</h3>
<div class="f_row ss_margintop">
<div class="f_col">
<div v-for="c in settingsUi.controls.keyboard.game" v-if="c.side == 'left'" 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 class="ss_margintop_xl">
<div v-for="c in settingsUi.controls.keyboard.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>
</div>
</div>
<div class="f_col ss_marginleft_xl">
<div v-for="c in settingsUi.controls.keyboard.game" v-if="c.side == 'right'" 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 class="ss_margintop">
<div v-for="t in settingsUi.adjusters.mouse" 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.mouse" 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>
</div>
</div>
</div>
</div>
<div id="settings_controller" v-show="showControllerTab">
<h3 class="nospace">{{ loc.p_settings_gamepadbindings }}</h3>
<div class="f_row ss_margintop">
<div class="f_col">
<div v-for="c in settingsUi.controls.gamepad.game" class="nowrap">
<settings-gamepad-binder :loc="loc" :control-id="c.id" :control-value="c.value" @control-captured="onGamepadGameControlCaptured" :controller-type="controllerType"></settings-gamepad-binder>
<div class="label">{{ loc[c.locKey] }}</div>
</div>
</div>
<div class="f_col ss_marginleft_xl">
<div class="ss_marginbottom_xl">
<div v-for="c in settingsUi.controls.gamepad.spectate" class="nowrap">
<settings-gamepad-binder :loc="loc" :control-id="c.id" :control-value="c.value" @control-captured="onGamepadSpectateControlCaptured" :controller-type="controllerType"></settings-gamepad-binder>
<div class="label">{{ loc[c.locKey] }}</div>
</div>
</div>
<div v-for="t in settingsUi.adjusters.gamepad" 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" :precision="t.precision" @setting-adjusted="onSettingAdjusted"></settings-adjuster>
</div>
<div v-for="t in settingsUi.togglers.gamepad" 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>
</div>
</div>
<p>{{ controllerId }}</p>
<p>{{ loc.p_settings_controllerhelp }} <a target="_blank" href="https://html5gamepad.com">html5gamepad.com</a></p>
</div>
<div id="settings_misc" v-show="showMiscTab">
<div class="f_row">
<div class="f_col">
<header>
<h2>{{loc.p_settings_volume_controls}}</h2>
</header>
<div v-for="t in settingsUi.adjusters.misc" 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.adjusters.music" 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>
<h3 class="nospace ss_margintop">{{ loc.p_settings_language }}</h3>
<language-selector :languages="languages" :loc="loc" :selectedLanguageCode="currentLanguageCode" class="ss_select"></language-selector>
<button v-if="showPrivacyOptions" @click="onPrivacyOptionsClicked" class="ss_button btn_blue bevel_blue btn_md ss_margintop_xl">{{ loc.p_settings_privacy }}</button>
</div>
<div class="f_col ss_marginleft_xl">
<div v-for="t in settingsUi.togglers.misc" 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>
</div>
</div>
</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="BAWK.play('ui_onchange')" 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) {
BAWK.play(sound);
},
reset: function () {
this.currentValue = (this.controlValue === null) ? 'undefined' : 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 {
BAWK.play('ui_onchange')
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) {
BAWK.play('ui_onchange')
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-gamepad-binder-template" type="text/x-template">
<button ref="gamepadInput" 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:focusout="onFocusOut($event)"
:key="controllerType">
<span v-html="currentValue"></span></button>
</script>
<script>
var comp_settings_gamepad_binder = {
template: '#settings-gamepad-binder-template',
props: ['loc', 'controlId', 'controlValue', 'controllerType'],
data: function () {
return {
currentValue: (this.controlValue === null) ? 'undefined' : vueData.controllerButtonIcons[this.controllerType][this.controlValue],
isCapturing: false
}
},
beforeUpdate: function () {
if (!this.isCapturing) {
this.setIcon(this.controlValue);
}
},
methods: {
playSound (sound) {
BAWK.play(sound);
},
reset: function () {
this.setIcon(this.controlValue);
this.isCapturing = false;
removeEventListener('gamepadbuttondown', this.onButtonDown);
removeEventListener('gamepadbuttonup', this.onButtonUp);
},
capture: function (value) {
this.isCapturing = false;
this.$refs.gamepadInput.blur();
this.$emit('control-captured', this.controlId, value);
this.reset();
},
onMouseDown: function (event) {
if (!this.isCapturing) {
this.currentValue = this.loc.press_button;
this.isCapturing = true;
addEventListener('gamepadbuttondown', this.onButtonDown);
addEventListener('gamepadbuttonup', this.onButtonUp);
}
},
onKeyDown: function (event) {
event.stopPropagation();
},
onKeyUp: function (event) {
event.stopPropagation();
},
onButtonDown: function (event) {
if (event.detail == 8 || event.detail == 9) return;
BAWK.play('ui_onchange')
this.capture(event.detail);
},
onFocusOut: function (event) {
this.reset();
},
setIcon: function (value) {
this.currentValue = (value === null) ? 'undefined' : vueData.controllerButtonIcons[this.controllerType][value];
}
},
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.setIcon(newValue);
}
}
};
</script><script id="settings-adjuster-template" type="text/x-template">
<div>
<h3 class="nospace">{{ loc[locKey] }}</h3>
<div class="f_row">
<input class="ss_slider" type="range" :min="min" :max="max" :step="step" v-model="currentValue" @change="onChange">
<label class="ss_slider label">{{ getCurrentValue() }}</label>
</div>
</div>
</script>
<script>
var comp_settings_adjuster = {
template: '#settings-adjuster-template',
props: ['loc', 'locKey', 'controlId', 'controlValue', 'min', 'max', 'step', 'multiplier', 'precision'],
data: function () {
return {
currentValue: this.controlValue
}
},
methods: {
onChange: function (event) {
this.$emit('setting-adjusted', this.controlId, this.currentValue);
BAWK.play('ui_onchange');
},
getCurrentValue: function () {
if (this.precision) {
return Number.parseFloat(this.currentValue).toFixed(this.precision);
}
else {
return Math.floor(this.currentValue * (this.multiplier || 1));
}
}
},
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);
BAWK.play('ui_onchange');
}
},
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,
'settings-gamepad-binder': comp_settings_gamepad_binder,
'language-selector': comp_language_selector,
'settings-adjuster': comp_settings_adjuster,
'settings-toggler': comp_settings_toggler
},
props: ['loc', 'settingsUi', 'languages', 'currentLanguageCode', 'showPrivacyOptions', 'controllerId', 'isFromEU', 'controllerType'],
data: function () {
return {
showKeyboardTab: true,
showControllerTab: false,
showMiscTab: false,
originalSettings: {},
showDetailSettings: false,
originalLanguage: '',
originalMusicVolume: '',
musicStatChg: ''
}
},
methods: {
selectTab: function (e) {
return this.switchTab(e.target.id)
},
switchTab(tab) {
this.showKeyboardTab = false;
this.showControllerTab = false;
this.showMiscTab = false;
switch (tab) {
case 'keyboard_button':
this.showKeyboardTab = true;
break;
case 'controller_button':
this.showControllerTab = true;
break;
case 'misc_button':
this.showMiscTab = true;
break;
}
BAWK.play('ui_toggletab');
},
captureOriginalSettings: function () {
this.originalSettings = deepClone(vueData.settingsUi);
this.originalLanguage = this.currentLanguageCode;
this.originalMusicVolume = this.originalSettings.adjusters.music[0].value;
},
applyOriginalSettings: function () {
vueData.settingsUi = this.originalSettings;
this.showDetailSettings = !vueData.settingsUi.togglers.misc.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.keyboard.game, id, value)
},
onSpectateControlCaptured: function (id, value) {
this.onControlCaptured(this.settingsUi.controls.keyboard.spectate, id, value)
},
onGamepadGameControlCaptured: function (id, value) {
this.onControlCaptured(this.settingsUi.controls.gamepad.game, id, value)
},
onGamepadSpectateControlCaptured: function (id, value) {
this.onControlCaptured(this.settingsUi.controls.gamepad.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);
Object.values(this.settingsUi.togglers).forEach(v => {
var toggler = v.find(t => { return t.id === id; });
if (toggler) toggler.value = value;
})
if (id === 'autoDetail') {
this.showDetailSettings = !value;
}
if (id === 'safeNames') {
extern.setSafeNames(value);
}
if (id === 'musicStatus') {
extern.setMusicStatus(value);
this.musicStatChg = true;
if (extern.inGame) {
vueApp.toggleMusic();
}
}
},
onSettingAdjusted: function (id, value) {
Object.values(this.settingsUi.adjusters).forEach(v => {
var adjuster = v.find( (a) => { return a.id === id; });
if (adjuster) adjuster.value = value;
})
if (id === 'volume') {
extern.setVolume(value);
}
if (id === 'mouseSpeed') {
extern.setMouseSpeed(value);
}
if (id === 'sensitivity') {
extern.setControllerSpeed(value);
}
if (id === 'deadzone') {
extern.setDeadzone(value);
}
if (id === 'musicVolume') {
extern.setMusicVolume(value);
}
},
onVolumeChange: function () {
extern.setVolume(this.settingsUi.volume);
},
onPrivacyOptionsClicked: function () {
this.$emit('privacy-options-opened');
BAWK.play('ui_popupopen');
},
onCancelClick: function () {
this.applyOriginalSettings();
extern.setMusicVolume(this.originalMusicVolume);
this.cancelLanguageSelect();
if (this.musicStatChg) {
if (extern.inGame) {
vueApp.toggleMusic();
}
};
this.$parent.close();
},
onCloseClick: function () {
this.applyOriginalSettings();
extern.setMusicVolume(this.originalMusicVolume);
this.cancelLanguageSelect();
if (this.musicStatChg) {
if (extern.inGame) {
vueApp.toggleMusic();
}
};
this.$parent.close();
BAWK.play('ui_popupclose');
},
quickSave() {
extern.applyUiSettings(this.settingsUi, this.originalSettings);
this.resetOriginalLanguage();
},
onSaveClick: function () {
if (vueApp.music.serverTracks.title) {
this.gaMusicVol();
}
this.gaMusicVol();
extern.applyUiSettings(this.settingsUi, this.originalSettings);
this.resetOriginalLanguage();
this.$parent.toggle();
BAWK.play('ui_playconfirm');
},
gaMusicVol() {
let newVol = Number(this.settingsUi.adjusters.music[0].value);
if (newVol === Number(this.originalMusicVolume)) return;
if ((Math.round(newVol*100)) <= 1) {
ga('send', 'event', 'music', 'mute', vueApp.music.serverTracks.title);
}
},
onResetClick: function () {
extern.resetSettings();
BAWK.play('ui_reset');
},
cancelLanguageSelect: function() {
this.originalLanguage === vueApp.$data.currentLanguageCode ?
vueApp.changeLanguage(vueApp.$data.currentLanguageCode) : vueApp.changeLanguage(this.originalLanguage);
// Revert localStore for language
localStore.setItem('languageSelected', this.originalLanguage);
this.resetOriginalLanguage();
},
resetOriginalLanguage: function() {
this.originalLanguage = '';
},
setSettings: function (settings) {
var getSettingById = (list, id) => {
return list.filter( o => {
return o.id == id;
})[0];
};
// Keyboard
getSettingById(this.settingsUi.controls.keyboard.game, 'up').value = settings.controls.keyboard.game.up;
getSettingById(this.settingsUi.controls.keyboard.game, 'down').value = settings.controls.keyboard.game.down;
getSettingById(this.settingsUi.controls.keyboard.game, 'left').value = settings.controls.keyboard.game.left;
getSettingById(this.settingsUi.controls.keyboard.game, 'right').value = settings.controls.keyboard.game.right;
getSettingById(this.settingsUi.controls.keyboard.game, 'jump').value = settings.controls.keyboard.game.jump;
getSettingById(this.settingsUi.controls.keyboard.game, 'fire').value = settings.controls.keyboard.game.fire;
getSettingById(this.settingsUi.controls.keyboard.game, 'scope').value = settings.controls.keyboard.game.scope;
getSettingById(this.settingsUi.controls.keyboard.game, 'reload').value = settings.controls.keyboard.game.reload;
getSettingById(this.settingsUi.controls.keyboard.game, 'swap_weapon').value = settings.controls.keyboard.game.swap_weapon;
getSettingById(this.settingsUi.controls.keyboard.game, 'grenade').value = settings.controls.keyboard.game.grenade;
getSettingById(this.settingsUi.controls.keyboard.spectate, 'ascend').value = settings.controls.keyboard.spectate.ascend;
getSettingById(this.settingsUi.controls.keyboard.spectate, 'descend').value = settings.controls.keyboard.spectate.descend;
// Gamepad
getSettingById(this.settingsUi.controls.gamepad.game, 'jump').value = settings.controls.gamepad.game.jump;
getSettingById(this.settingsUi.controls.gamepad.game, 'fire').value = settings.controls.gamepad.game.fire;
getSettingById(this.settingsUi.controls.gamepad.game, 'scope').value = settings.controls.gamepad.game.scope;
getSettingById(this.settingsUi.controls.gamepad.game, 'reload').value = settings.controls.gamepad.game.reload;
getSettingById(this.settingsUi.controls.gamepad.game, 'swap_weapon').value = settings.controls.gamepad.game.swap_weapon;
getSettingById(this.settingsUi.controls.gamepad.game, 'grenade').value = settings.controls.gamepad.game.grenade;
getSettingById(this.settingsUi.controls.gamepad.spectate, 'ascend').value = settings.controls.gamepad.spectate.ascend;
getSettingById(this.settingsUi.controls.gamepad.spectate, 'descend').value = settings.controls.gamepad.spectate.descend;
// Misc
getSettingById(this.settingsUi.adjusters.misc, 'volume').value = settings.volume;
getSettingById(this.settingsUi.adjusters.music, 'musicVolume').value = settings.musicVolume;
getSettingById(this.settingsUi.adjusters.mouse, 'mouseSpeed').value = settings.mouseSpeed;
getSettingById(this.settingsUi.adjusters.gamepad, 'sensitivity').value = settings.controllerSpeed;
getSettingById(this.settingsUi.adjusters.gamepad, 'deadzone').value = settings.deadzone;
getSettingById(this.settingsUi.togglers.mouse, 'mouseInvert').value = (settings.mouseInvert !== 1);
getSettingById(this.settingsUi.togglers.gamepad, 'controllerInvert').value = (settings.controllerInvert !== 1);
getSettingById(this.settingsUi.togglers.misc, 'holdToAim').value = settings.holdToAim;
getSettingById(this.settingsUi.togglers.misc, 'enableChat').value = settings.enableChat;
getSettingById(this.settingsUi.togglers.misc, 'safeNames').value = settings.safeNames;
getSettingById(this.settingsUi.togglers.misc, 'autoDetail').value = settings.autoDetail;
getSettingById(this.settingsUi.togglers.misc, 'shadowsEnabled').value = settings.shadowsEnabled;
getSettingById(this.settingsUi.togglers.misc, 'highRes').value = settings.highRes;
getSettingById(this.settingsUi.togglers.misc, 'musicStatus').value = settings.musicStatus;
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">
<div class="overlay_dark popup_lg roundme_md">
<h4 >{{loc.browser_known_issues_title}}</h4>
<p>{{loc.browser_known_chrome84_issues_desc}}</p>
</div>
<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="BAWK.play('ui_click')" @change="BAWK.play('ui_onchange')">
<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) {
BAWK.play(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;
BAWK.play('ui_toggletab');
! this.showTab1 && ga('send', 'event', 'feedback opened');
},
onBackClick: function () {
vueApp.$refs.helpPopup.toggle();
BAWK.play('ui_popupclose');
},
onSendClick: function () {
this.doValidation = true;
if (!this.validateEmail() || !this.validateMessage()) {
return;
}
BAWK.play('ui_playconfirm');
// Send that shit out
extern.api_feedback(this.selectedType, this.email, this.feedback);
setTimeout(() => {
this.$parent.toggle();
this.selectedType = 0;
this.feedback = null;
this.email = null;
}, 900);
}
}
};
</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="display-grid grid-column-4-eq grid-gap-space-lg">
<egg-store-item v-for="item in eggStoreItems" :key="item.sku" :item="item" :loc="loc" inStore="true" :account-set="accountSettled"></egg-store-item>
</div>
<!-- <div v-if="showGoldenChicken" 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">${{eggStoreItems[4].price}} USD</div>
<button class="ss_button btn_green bevel_green width_md center_h" @click="onItemClicked(eggStoreItems[4].sku)" @click="onItemClicked(item.sku)">{{ loc.p_chicken_goldbutton }}</button>
</div>
</div> -->
</div>
</script>
<template id="comp-store-item">
<figure id="popupInnards" v-if="showItem" class="single-egg-store-item box_blue4 roundme_md f_col center_cont box_relative" :class="[itemType, {purchased: purchased}]">
<div v-if="purchased" class="single-egg-store-item-purchased">{{loc.p_egg_shop_purchased}}</div>
<div v-if="item.flagText" id="eggshop_banner" :class="{sale: item.salePrice}">
<img v-if="!item.salePrice && !item.itemId" src="img/egg-shop-banner-left.png">
<div class="eggshop_banner_mid">
<i v-if="item.salePrice || item.itemId" class="fas" :class="flagTxt"></i>
{{ item.discount }} {{ loc[item.flagText] }}
</div>
</div>
<figcaption>
<p align="center" class="nospace roundme_md"><img :src="item.img" class="eggshop_image roundme_md"></p>
<h6 class="nospace shadow_bluebig4 eggshop_bigtitle">{{ loc[item.title] }}</h6>
<span class="eggshop_subtitle text_white">{{ loc[item.desc] }}</span>
<div class="f_row">
<div class="eggshop_pricebox roundme_sm" :class="{ slashed: item.salePrice }">${{ item.price }} USD</div>
<div v-if="item.salePrice" class="eggshop_pricebox roundme_sm sale-price">${{ item.salePrice }} USD</div>
</div>
<button class="store_btn ss_button btn_green bevel_green btn_sm center_h" @click="onItemClicked(item.sku)">{{ buyBtnText }}</button>
</figcaption>
</figure>
</template>
<script>
const comp_store_item = {
template: '#comp-store-item',
props: ['loc', 'item', 'inStore', 'accountSet'],
data() {
return {
purchased: false,
attempt: 0,
};
},
methods: {
onItemClicked() {
if (!this.accountSet || !vueApp.accountSettled) {
vueApp.hideEggStorePopup();
setTimeout(() => {
if (this.attempt < 5) {
this.onItemClicked(this.item.sku);
this.attempt++;
} else {
vueApp.showGenericPopup('uh_oh', 'error', 'ok');
}
}, 300);
vueApp.pleaseWaitPopup();
return;
}
if (this.$parent.$el.id === 'help') {
this.$parent.$parent.hide();
} else {
this.$parent.hide();
}
if (this.purchased) {
console.log('Item is owned so lets go see it.');
vueApp.showItemOnEquipScreen(extern.catalog.findItemById(this.item.itemId));
return;
}
extern.buyProductForMoney(this.item.sku);
ga('send', 'event', vueApp.googleAnalytics.cat.purchases, vueApp.googleAnalytics.action.eggShackProductClick, this.item.sku);
},
isPurchased() {
if (this.item.itemId) {
return this.purchased = extern.isItemOwned(this.item.itemId);
}
},
},
computed: {
itemType() {
return 'single-egg-store-item-is-' + this.item.type;
},
buyBtnText() {
if (this.purchased) {
return this.loc.p_egg_shop_see_item;
}
return this.loc.p_buy_item_confirm;
},
showItem() {
if (this.inStore) return this.item.inStore;
this.isPurchased();
return true;
},
flagTxt() {
if (this.item.salePrice) {
return 'fa-tag';
}
return 'fa-gem'
}
},
watch: {
accountSet(val) {
if (val) {
this.isPurchased();
}
}
}
};
</script>
<script>
var comp_egg_store = {
template: '#egg-store-template',
components: {
'egg-store-item': comp_store_item,
},
data() {
return vueData;
},
props: ['loc'],
methods: {
onItemClicked: function (sku) {
if (!this.accountSettled) {
console.log(this.$parent.hide());
setTimeout(() => {
this.onItemClicked(sku)
}, 300);
vueApp.pleaseWaitPopup();
return;
}
if (vueApp.$refs.genericPopup.isShowing === true) vueApp.$refs.genericPopup.close();
this.$parent.hide();
extern.buyProductForMoney(sku);
ga('send', 'event', this.googleAnalytics.cat.purchases, this.googleAnalytics.action.eggShackProductClick, 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();
BAWK.play('ui_click');
extern.clickedHouseAdBig(this.useAd);
},
close: function () {
if (this.useAd === null) return;
vueApp.toggleTitleScreenAd();
BAWK.play('ui_popupclose');
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;
vueApp.toggleTitleScreenAd();
}, 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 () {
BAWK.play('ui_click');
extern.clickedHouseAdSmall(this.useAd);
}
},
computed: {
adImageUrl: function () {
if (!hasValue(this.useAd)) {
return;
}
ga('send', 'event', {
eventCategory: 'House banner ad',
eventAction: 'show',
eventLabel: this.useAd.label
});
return 'img/promo/{0}{1}'.format(this.useAd.id, this.useAd.imageExt);
}
}
};
</script>
<script id="item-template" type="text/x-template">
<div v-if="!showPhysicalMerch" v-show="!hidetheButterFly" class="store_item roundme_lg clickme" ref="eggItemInvetory" :class="highlightSelected()" @click="onClick">
<div v-if="isPremium" class="store_item-premium">
Premium
</div>
<div v-if="showPrice" class="equip_smallprice">
<svg v-if="!isPremium" class="equip_egg eggIcon"><use xlink:href="#icon-egg"></use></svg>
<i v-if="isPremium" class="fas fa-dollar-sign equip_egg eggIcon"></i>
<div class="equip_cost"> {{ getPriceSku }}</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 () {
return this.isItemSellable() && this.item.unlock === 'physical';
},
hidetheButterFly() {
return this.isItemSellable() && this.item.id === 1160
},
isPremium() {
return this.item.unlock === 'premium';
},
getPriceSku() {
const premItem = vueData.eggStoreItems.filter(item => item.itemId.id === this.item.id)[0];
if (premItem) {
this.item.sku = premItem.sku;
this.item.price = premItem.salePrice ? premItem.salePrice : premItem.price;
return this.item.price;
}
return this.item.price;
}
},
mounted() {
this.renderItem();
this.itemHightlightedOrder();
},
methods: {
isItemSellable: function () {
return !this.itemOnly && vueData.equip.mode == vueData.equip.equipModes.shop;
},
renderItem: function () {
if (this.showPhysicalMerch && vueData.equip.mode == vueData.equip.equipModes.shop) return;
extern.renderItemToCanvas(this.item, this.$refs.itemCanvas);
},
highlightSelected: function () {
return this.isSelected ? 'highlight' : '';
},
onClick: function () {
this.$emit('item-selected', this.item);
},
itemHightlightedOrder: function() {
if (this.showPhysicalMerch && vueData.equip.mode == vueData.equip.equipModes.shop) return;
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 v-if="showGoldenChicken" 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 v-if="showNugget" 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',
data: function () {
return vueData;
},
props: ['loc'],
methods: {
onCloseClick: function () {
this.$parent.close();
BAWK.play('ui_popupclose');
},
onChickenClick: function () {
document.exitPointerLock();
window.onkeydown = null;
window.onkeyup = null;
this.$parent.toggle();
extern.buyGoldenChicken();
BAWK.play('ui_playconfirm');
ga('send', 'event', this.googleAnalytics.cat.purchases, this.googleAnalytics.action.goldenChickenProductClick, `Get It Now`);
},
onNuggetClick: function () {
if (!vueData.firebaseId) {
this.$parent.hide();
vueApp.showGenericPopup('p_redeem_error_no_player_title', 'p_redeem_error_no_player_content', 'ok');
return;
}
if (!this.accountSettled) {
setTimeout(() => {
this.onNuggetClick();
}, 300);
this.$parent.hide();
vueApp.pleaseWaitPopup();
return;
}
this.$parent.hide();
extern.startChickenNugget();
BAWK.play('ui_playconfirm');
ga('send', 'event', this.googleAnalytics.cat.purchases, this.googleAnalytics.action.goldenChickenNuggetClick, `Try It Out`);
}
}
};
</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>
<p align="center">
<button id="gotNuggetOK" v-show="isMiniGameComplete" @click="onGotNugget" class="ss_button btn_shiny clickme invisible">{{ loc.p_nugget_button }}</button>
</p>
<iframe id="miniGameFrame" ref="miniGameFrame" src="about:blank" frameBorder="0" class="roundme_lg" ></iframe>
<div class="center_cont">
<display-ad id="shellshockers_chicken_nugget_banner" ref="nuggetDisplayAd" class="pauseAdPlacement" :adUnit="adUnits.display.nugget" pokiAdSize="728x90"></display-ad>
</div>
</div>
</script>
<script>
var comp_chicken_nugget_popup = {
template: '#chicken-nugget-template',
props: ['loc'],
data: function () {
return vueData;
},
methods: {
placeBannerAdTag: function (tagEl) {
this.$refs.chickenNuggetAdContainer.appendChild(tagEl);
},
loadMiniGame: function () {
this.isMiniGameComplete = false;
this.$refs.miniGameFrame.src = "app_nugget/index.html";
this.$refs.nuggetDisplayAd.show();
},
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" ref="bigHouseAd" :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>
<!-- <pwa-button :show="ui.showCornerButtons"></pwa-button> -->
<!-- <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="accountPanelHome" :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" :isEggStoreSale="isEggStoreSaleItem" @sign-in-clicked="onSignInClicked" @sign-out-clicked="onSignOutClicked"></account-panel>
<div id="logo">
<a href="https://www.shellshock.io" @click="BAWK.play('ui_click')"><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" :is-game-ready='accountSettled' :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>
<!--<music-widget :loc="loc" :settings-ui="settingsUi" ref="homeMusicWidget" :playBtn="true" :volumeSlider="true" :settings="true" :show="true"></music-widget>-->
</div>
<div id="panel_front_egg"">
<div class="paper-doll--click-container" @click="clickEggToPlay"></div>
<weapon-select-panel id="weapon_select" :loc="loc" :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">
<event-panel :show-soon="true" :show-ui="true"></event-panel>
<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" :items="newsfeedItems" :current-language-code="currentLanguageCode"></newsfeed-panel>
</div>
<!-- <house-ad-small id="banner-ad" :useAd="ui.houseAds.small"></house-ad-small> -->
<display-ad id="shellshockers_titlescreen_wrap" ref="titleScreenDisplayAdd" class="house-ad-small" :adUnit="adUnits.display.home" pokiAdSize="300x250"></display-ad>
</div>
</div>
<div id="mainFooter">
<chicken-panel ref="chickenPanel" id="chicken_panel" :local="loc" :do-upgraded="isUpgraded"></chicken-panel>
<footer-links-panel id="footer_links_panel" :loc="loc"></footer-links-panel>
</div>
<div id="gameDescription">
<h1 align="center">{{ loc.home_desc_about }}</h1>
<p align="center">{{ loc.home_desc_pick }}
<svg class="eggIcon"><use xlink:href="#icon-egg"></use></svg>
{{ loc.home_desc_loadout }}
<svg class="eggIcon"><use xlink:href="#icon-egg"></use></svg>
{{ loc.home_desc_madeof }}</p>
<div style="width: 48%; float: left; margin-right: 2em; ">
<p>{{ loc.home_desc_p1 }}</p>
<p><img src="img/eggPose05.png" style="width: 350px; float: left; margin-right: 1em; shape-outside: polygon(0% 0%, 100% 0%, 100% 41%, 84% 48%, 80% 63%, 59% 74%, 46% 100%, 0% 99%);">{{ loc.home_desc_p2 }}</p>
</div>
<div style="width: 48%; float: left;">
<p>{{ loc.home_desc_p3 }}
<img src="img/eggPose01.png" style="float: right; margin-left: 1em; margin-top: 1em; shape-outside: polygon(1% 0%, 100% 1%, 100% 99%, 50% 100%, 28% 86%, 16% 68%, 14% 51%, 0 35%);">
{{ loc.home_desc_p4 }}</p>
<p>{{ loc.home_desc_p5 }}</p>
<p>{{ loc.home_desc_p6 }}</p>
</div>
<h1 align="center" style="clear: both;">{{ loc.home_desc_controls }}</h1>
<p>{{ loc.home_desc_standard }}</p>
<ul>
<li> {{ loc.home_desc_control1 }}</li>
<li> {{ loc.home_desc_control2 }}</li>
<li> {{ loc.home_desc_control3 }}</li>
<li> {{ loc.home_desc_control4 }}</li>
<li> {{ loc.home_desc_control5 }}</li>
<li> {{ loc.home_desc_control6 }}</li>
</ul>
<p align="center"><button class="ss_button btn_yolk bevel_yolk" @click="vueApp.scrollToTop()">{{ loc.home_backtotop }}</button></p>
</div>
<!-- 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="BAWK.play('ui_click')" @change="BAWK.play('ui_onchange')">
<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">
{{ vueData.maps[mapIdx].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>{{vueData.maps[mapIdx].numPlayers}}</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', 'isGameReady'],
data: function () {
return {
showingServerList: false,
pickedGameType: 0,
gameTypes: vueData.gameTypes,
mapIdx: 0,
mapImgPath: this.mapImgBasePath + vueData.maps[0].filename + '.png?' + vueData.maps[0].hash,
mapLocKey: vueData.maps[0].locKey,
playClickedBeforeReady: false,
vueData,
}
},
methods: {
playSound (sound) {
BAWK.play(sound);
},
onCloseClick: function () {
this.$parent.close();
BAWK.play('ui_popupclose');
},
onServerClick: function () {
this.showingServerList = true;
this.$parent.toggle();
vueApp.$refs.homeScreen.$refs.playPanel.$refs.pickServerPopup.toggle();
BAWK.play('ui_click');
},
onMapChange: function(dir) {
this.mapIdx = ((this.mapIdx + dir) + vueData.maps.length) % vueData.maps.length;
this.mapImgPath = this.mapImgBasePath + vueData.maps[this.mapIdx].filename + '.png?' + vueData.maps[this.mapIdx].hash;
this.mapLocKey = vueData.maps[this.mapIdx].locKey;
BAWK.play('ui_onchange');
},
onPlayTypeWhenSignInComplete() {
return this.playClickFunction();
},
onPlaySentBeforeSignIn() {
this.gameClickedBeforeReady = true;
vueApp.showSpinner('signin_auth_title', 'signin_auth_msg');
},
onPlayClick: function () {
this.$parent.close();
if (!this.isGameReady) {
this.onPlaySentBeforeSignIn();
return;
}
vueApp.externPlayObject(vueData.playTypes.createPrivate, this.pickedGameType, this.vueData.playerName, this.mapIdx, '');
BAWK.play('ui_playconfirm');
}
},
watch: {
isGameReady(val) {
if (this.gameClickedBeforeReady && val) {
setTimeout(() => this.onPlayClick(), 700);
}
}
}
};
</script><script id="account-panel-template" type="text/x-template">
<div>
<div id="account_top">
<eggstore-notify ref="eggStoreSaleNotify" :show="isEggStoreSale" :loc="loc" :sku="sku"></eggstore-notify>
<div class="account_eggs roundme_sm clickme" @click="onEggStoreClick" v-bind:title="loc['account_title_eggshop']">
<button v-if="isAnonymous" type="image" src="img/attention_indicator.png" v-show="showCornerButtons" @click="onAnonWarningClick" class="ss_button btn_yolk bevel_yolk attention_btn" v-bind:title="loc['account_title_shop']"><i class="fas fa-exclamation"></i></button>
<img src="img/ico_goldenEgg.png" class="egg_icon">
<span class="egg_count shadow_blue2_micro">{{ eggBalance }}</span>
</div>
<!-- <input type="image" src="img/ico_nav_leaderboards.png" class="account_icon roundme_sm"> -->
<div id="corner-buttons" v-show="showCornerButtons">
<input type="image" src="img/ico_nav_shop.png" @click="itemStoreClick" class="account_icon roundme_sm" v-bind:title="loc['account_title_shop']">
<input type="image" src="img/ico_nav_help.png" @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" @click="onSettingsClick" class="account_icon roundme_sm" v-bind:title="loc['account_title_settings']">
<input type="image" src="img/ico_nav_fullscreen.png" v-if="!vueData.isPoki" @click="onFullscreenClick" class="account_icon roundme_sm" v-bind:title="loc['account_title_fullscreen']">
</div>
</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>
<template id="egg-store-notify">
<div v-if="show" class="egg-store-sale-notify" @click="notifyClick">
<button class="account_icon roundme_sm account_icon-item"><i aria-hidden="true" class="fas fa-gem"><span class="hideme">Egg</span></i>
<span class="text"> {{loc.p_egg_shop_sale_notify}}</span>
</button>
</div>
</template>
<script>
const compEggStoreSaleNotify = {
template: '#egg-store-notify',
props: ['loc', 'show', 'sku'],
methods: {
notifyClick() {
if (!vueData.firebaseId) {
vueApp.showGenericPopup('p_redeem_error_no_player_title', 'p_redeem_error_no_player_content', 'ok');
return;
}
ga('send', 'event', 'Purchases', 'Sale notify click', this.$parent.$parent.$el.id);
vueApp.eggStoreReferral = 'Sale notify ref';
console.log('sku', this.sku);
if (this.sku) {
return vueApp.showPopupEggStoreSingle(this.sku)
}
return vueApp.showEggStorePopup();
}
}
};
</script><script>
var comp_account_panel = {
template: '#account-panel-template',
components: {
'language-selector': comp_language_selector,
'eggstore-notify': compEggStoreSaleNotify,
},
props: ['loc', 'eggs', 'languages', 'selectedLanguageCode', 'showBottom', 'photoUrl', 'isAnonymous', 'isOfAge', 'showTargetedAds', 'showCornerButtons', 'ui', 'isEggStoreSale', 'sku'],
data: function () {
return {
languageCode: this.selectedLanguageCode,
eggBalance: 0,
vueData,
}
},
created() {
this.getEggsLocalStorage();
},
methods: {
getEggsLocalStorage() {
const raw = localStore.getItem('localLoadOut');
if (!raw) {
return;
}
const storage = JSON.parse(raw);
if (!'balance' in storage) {
return;
}
return this.eggBalance = storage.balance;
},
onEggStoreClick: function () {
if (!vueData.firebaseId) {
vueApp.showGenericPopup('p_redeem_error_no_player_title', 'p_redeem_error_no_player_content', 'ok');
return;
}
vueApp.showEggStorePopup();
BAWK.play('ui_popupopen');
ga('send', 'event', this.vueData.googleAnalytics.cat.purchases, this.vueData.googleAnalytics.action.eggShackClick);
},
itemStoreClick: function() {
if (extern.inGame) {
vueApp.$refs.gameScreen.hideGameMenu();
extern.openEquipInGame();
vueApp.switchToEquipUi();
}
else {
vueApp.switchToEquipUi();
}
vueApp.$refs.equipScreen.switchToShop();
BAWK.play('ui_popupopen');
},
onHelpClick: function () {
vueApp.showHelpPopup();
ga('send', 'event', vueApp.googleAnalytics.cat.playerStats, vueApp.googleAnalytics.action.faqPopupClick);
BAWK.play('ui_popupopen');
},
onSettingsClick: function () {
ga('send', 'event', 'open settings');
vueApp.showSettingsPopup();
BAWK.play('ui_popupopen');
},
onFullscreenClick: function () {
extern.toggleFullscreen();
BAWK.play('ui_click');
},
onSignInClicked: function () {
vueApp.setDarkOverlay(true);
this.$emit('sign-in-clicked');
BAWK.play('ui_playconfirm');
},
onSignOutClicked: function () {
vueApp.setDarkOverlay(true);
this.$emit('sign-out-clicked');
BAWK.play('ui_reset');
},
onShareLinkClick: function () {
extern.inviteFriends();
},
onAnonWarningClick: function() {
ga('send', 'event', vueApp.googleAnalytics.cat.playerStats, vueApp.googleAnalytics.action.anonymousPopupOpen);
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);
}
},
watch: {
eggs() {
this.eggBalance = this.eggs;
}
}
};
</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="BAWK.play('ui_click')">
<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) {
BAWK.play(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 class="stats-wrapper">
<div id="stat_item" class="roundme_sm">
<h4>{{ loc.kills.toUpperCase() }}</h4>
<div class="stat_stat">{{ lKills }}</div>
</div>
<div id="stat_item" class="roundme_sm">
<h4>{{ loc.deaths.toUpperCase() }}</h4>
<div class="stat_stat">{{ lDeaths }}</div>
</div>
<div id="stat_item" class="roundme_sm">
<h4>{{ loc.kdr.toUpperCase() }}</h4>
<div class="stat_stat">{{ lKdr }}</div>
</div>
<div id="stat_item" class="roundme_sm">
<h4>{{ loc.streak.toUpperCase() }}</h4>
<div class="stat_stat">{{ lStreak }}</div>
</div>
</div>
</div>
</template>
<script>
var comp_stats_panel = {
template: '#stats_panel_template',
props: ['loc', 'kills', 'deaths', 'kdr', 'streak'],
data: () => {
return {
localLoadOut : Object,
lKills: 0,
lDeaths: 0,
lKdr: 0,
lStreak: 0,
}
},
created() {
this.getStatsLocalStorage();
},
methods: {
getStatsLocalStorage() {
const raw = localStore.getItem('localLoadOut');
if (!raw) {
return;
}
const storage = JSON.parse(raw);
const {kills, deaths, kdr, streak} = storage;
this.lKills = kills;
this.lDeaths = deaths;
this.lKdr = kdr;
this.lStreak = streak;
},
},
watch: {
kills() {
this.lKills = this.kills;
this.lDeaths = this.deaths;
this.lKdr = this.kdr;
this.lStreak = this.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" :disabled="isButtonDisabled" 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_yolk bevel_yolk fullwidth nospace play-button"><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" :is-game-ready="isGameReady" map-img-base-path="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="BAWK.play('ui_onchange')">
<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) {
BAWK.play(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();
BAWK.play('ui_popupclose');
},
onConfirmClick: function () {
this.$emit('server-picked', this.serverId);
this.$parent.close();
BAWK.play('ui_playconfirm');
}
}
};
</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', 'isGameReady'],
data: function() {
return {
pickedServerId: null,
pickedGameType: this.currentGameType,
isButtonDisabled: true,
playClickedBeforeReady: false,
playClickFunction: Function,
}
},
methods: {
onPickServerButtonClick: function () {
this.$refs.pickServerPopup.toggle();
BAWK.play('ui_popupopen');
},
onServerPicked: function (serverId) {
if (vueData.currentServerId === serverId) { return; }
vueData.currentServerId = serverId;
extern.selectServer(vueData.currentServerId);
BAWK.play('ui_onchange');
},
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);
BAWK.play('ui_onchange');
},
onPlayTypeWhenSignInComplete() {
return this.playClickFunction();
},
onPlaySentBeforeSignIn(callback) {
this.gameClickedBeforeReady = true;
vueApp.showSpinner('signin_auth_title', 'signin_auth_msg');
this.playClickFunction = callback;
},
hasValidPlayerNameCheck() {
console.log('invalid player name');
vueApp.showGenericPopup('play_pu_name_title', 'play_pu_name_content', 'ok');
vueApp.hideSpinner();
return;
},
onPlayButtonClick: function () {
if (!hasValue(this.playerName)) {
this.hasValidPlayerNameCheck();
return;
}
if (!this.isGameReady) {
this.onPlaySentBeforeSignIn(this.onPlayButtonClick);
return;
}
vueApp.disablePlayButton(true);
vueApp.game.respawnTime = 0;
vueApp.externPlayObject(vueData.playTypes.joinPublic, this.pickedGameType, this.playerName, -1, '');
BAWK.play('ui_playconfirm');
},
onCreatePrivateGameClick: function () {
this.$refs.createPrivateGamePopup.toggle();
BAWK.play('ui_popupopen');
},
onJoinPrivateGameClick: function () {
this.showJoinPrivateGamePopup(vueData.home.joinPrivateGamePopup.code);
BAWK.play('ui_popupopen');
},
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 () {
if (!hasValue(this.playerName)) {
this.hasValidPlayerNameCheck();
return;
}
if (!this.isGameReady) {
this.onPlaySentBeforeSignIn(this.onJoinConfirmed)
return;
}
vueData.home.joinPrivateGamePopup.code = vueData.home.joinPrivateGamePopup.code.replace(parsedUrl.root, '');
this.$refs.joinPrivateGamePopup.hide();
vueApp.externPlayObject(vueData.playTypes.joinPrivate, '', this.playerName, '', 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;
},
isGameReady(val) {
this.isButtonDisabled = val ? false : true;
if (this.gameClickedBeforeReady && val) {
this.onPlayTypeWhenSignInComplete()
}
}
}
};
</script><template id="weaponselect_panel_template" type="text/x-template">
<div :class="{disabled: !vueData.accountSettled}">
<div class="tool-tip">
<img src="img/ico_weapon_assaultRifle.png" class="weapon_img roundme_lg" :class="addSelectedCssClass(charClass.Soldier)" @click="selectClass(charClass.Soldier)"><span><strong>{{loc.weapon_soldier_title}}:</strong> {{loc.weapon_soldier_content}}</span>
</div>
<div class="tool-tip">
<img src="img/ico_weapon_shotgun.png" class="weapon_img roundme_lg" :class="addSelectedCssClass(charClass.Scrambler)" @click="selectClass(charClass.Scrambler)"><span><strong>{{loc.weapon_scrambler_title}}: </strong> {{loc.weapon_scrambler_content}}</span>
</div>
<div class="tool-tip">
<img src="img/ico_weapon_sniper.png" class="weapon_img roundme_lg" :class="addSelectedCssClass(charClass.Ranger)" @click="selectClass(charClass.Ranger)"><span><strong>{{loc.weapon_ranger_title}}: </strong>{{loc.weapon_ranger_content}}</span>
</div>
<div class="tool-tip">
<img src="img/ico_weapon_rocketLauncher.png" class="weapon_img roundme_lg" :class="addSelectedCssClass(charClass.Eggsploder)" @click="selectClass(charClass.Eggsploder)"><span><strong>{{loc.weapon_eggsploder_title}}: </strong> {{loc.weapon_eggsploder_content}}</span>
</div>
<div class="tool-tip">
<img src="img/ico_weapon_SMG.png" class="weapon_img roundme_lg" :class="addSelectedCssClass(charClass.Whipper)" @click="selectClass(charClass.Whipper)"><span><strong>{{loc.weapon_whipper_title}}: </strong>{{loc.weapon_whipper_content}}</span>
</div>
<div class="tool-tip">
<img src="img/ico_weapon_boltAction.png" class="weapon_img roundme_lg" :class="addSelectedCssClass(charClass.Crackshot)" @click="selectClass(charClass.Crackshot)"><span><strong>{{loc.weapon_crackshot_title}}: </strong>{{loc.weapon_crackshot_content}}</span>
</div>
</div>
</template>
<script>
var comp_weapon_select_panel = {
template: '#weaponselect_panel_template',
props: ['currentClass', 'loc'],
data: function () {
return {
charClass: CharClass,
vueData,
}
},
methods: {
selectClass: function (classIdx) {
if (!vueData.accountSettled){
return;
}
extern.changeClass(classIdx);
this.$emit('changed-class', classIdx);
BAWK.play('ui_click');
},
addSelectedCssClass: function (classIdx) {
return (this.currentClass === classIdx)
? 'weapon_selected'
: '';
},
}
// watch: {
// accountSettled(val) {
// }
// }
};
</script>
<script id="newsfeed-panel-template" type="text/x-template">
<section class="v_scroll">
<article v-if="items" v-for="item in items" v-if="item.active" @click="onItemThatIsClicked(item)" class="news_item roundme_md clickme">
<img :src="imageSrc(item)" class="news_img roundme_sm">
<p>{{ item.content }}</p>
</article>
</section>
</script>
<script>
var comp_newsfeed_panel = {
template: '#newsfeed-panel-template',
props: ['items'],
data: function () {
return vueData;
},
// mounted: function () {
// // this.fetchWebData();
// this.checklocalForNewsData();
// },
methods: {
imageSrc(item) {
return 'img/newsItems/' + item.id + item.imageExt;
},
onItemThatIsClicked(item) {
console.log(item);
extern.clickedWebFeedItem(item);
BAWK.play('ui_click');
},
},
};
</script><script id="chicken-panel-template" type="text/x-template">
<div id="showBuyPassDialogButton" class="new">
<div class="chicken-panel--upgraded" v-show="doUpgraded">
<div class="tool-tip tool-tip--right">
<span v-if="nugCounter" id="nugget-countdown">{{nugCounter}} Minutes remaining.</span>
<img class="upgraded-nugget" src="img/chicken-nugget/goldenNugget_static.png">
<!-- <div id="nugget-timer" class="nugget-timer--wrapper">
<div class="timer-background"></div>
<div class="timer spinner"></div>
<div class="timer filler"></div>
<div class="mask"></div>
</div> -->
</div>
</div>
<div class="chicken-panel--no-upgraded" v-show="!doUpgraded">
<img src="img/chicken-nugget/starburst.png" @click="onChickenClick" class="clickme starburst">
<img src="img/chicken-nugget/goldenNuggetGIFWIP.gif" @click="onChickenClick" class="clickme nugget-chick">
<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: ['local', 'doUpgraded'],
data: function () {
return vueData;
},
methods: {
onChickenClick: function () {
BAWK.play('ui_chicken');
vueApp.showGoldChickenPopup();
ga('send', 'event', this.googleAnalytics.cat.purchases, 'Golden Chicken Click');
},
setupNuggetTimer() {
if ((!this.isUpgraded || this.nugStart === null || !this.nugStart) && !this.isBuyNugget)
return;
if (this.isBuyNugget) {
const fauxStart = new Date();
const fH = fauxStart.getHours() + 1;
this.nugStart = new Date().setHours(fH);
}
const current = new Date(Date.now()),
end = new Date(this.nugStart),
tz = ! this.isBuyNugget ? end.getTimezoneOffset() / 60 : 0,
cHr = current.getHours() + tz,
now = new Date().setHours(cHr),
timer = document.getElementById('nugget-timer');
for (let i = 0; i < timer.children.length; i++) {
timer.children[i].style.animationDelay = (Math.floor(end - (now)) / 1000) - 3600 + 's';
}
this.initTimer(end);
},
timeRemaining(end) {
const t = Date.parse(end) - Date.parse(new Date()),
minutes = Math.floor( (t/1000/60) % 60 ),
hours = Math.floor( (t/(1000*60*60)) % 24 );
return {
'total': t,
'hours': hours,
'minutes': minutes,
};
},
initTimer(end) {
const counter = setInterval(() => {
const t = this.timeRemaining(end);
this.nugCounter = t.minutes;
if (t.minutes <= 0)
clearInterval(counter);
}, 3000);
},
},
};
</script><script id="footer-links-panel-template" type="text/x-template">
<footer class="main-footer">
<nav class="center_h">
<a @click="onChangelogClicked" class="clickme">{{ version }}</a> |
<!-- <a href="https://shell-shockers.myshopify.com/collections/all" target="_blank" @click="BAWK.play('ui_click')">{{ loc.footer_merchandise }}</a> | -->
<a href="https://www.bluewizard.com/privacypolicy" target="_blank" @click="BAWK.play('ui_click')">{{ loc.footer_privacypolicy }}</a> |
<a href="https://bluewizard.com/terms/" target="_blank" @click="BAWK.play('ui_click')">{{ loc.footer_termsofservice }}</a> |
<a href="https://www.bluewizard.com" target="_blank" @click="BAWK.play('ui_click')">© 2020 {{ loc.footer_bluewizard }}</a> |
</nav>
<div class="social-icons">
<social-panel id="social_panel"></social-panel>
</div>
</footer>
</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="BAWK.play('ui_click')"></a>
<a href="https://discord.gg/bluewizard" target="_blank"><img src="img/ico_social_discord.png" class="social_icon" @click="BAWK.play('ui_click')"></a>
<a href="https://www.facebook.com/ShellShockersGame" target="_blank"><img src="img/ico_social_facebook.png" class="social_icon" @click="BAWK.play('ui_click')"></a>
<a href="https://twitter.com/eggcombat" target="_blank"><img src="img/ico_social_twitter.png" class="social_icon" @click="BAWK.play('ui_click')"></a>
</div>
</script>
<script>
var comp_social_panel = {
template: '#social-panel-template',
methods: {
playSound (sound) {
BAWK.play(sound);
}
}
};
</script>
<script>
var comp_footer_links_panel = {
template: '#footer-links-panel-template',
components: {
'social-panel': comp_social_panel,
},
props: ['loc'],
data: function () {
return {
version: version
}
},
methods: {
onChangelogClicked: function () {
vueApp.showChangelogPopup();
BAWK.play('ui_popupopen');
},
playSound (sound) {
BAWK.play(sound);
}
}
};
</script>
<template id="music-widget">
<div v-if="isMusic" class="music-widget roundme_md" :class="[!show ? hideClass : '']">
<div v-if="theAudio" class="music-widget--wrapper flex flex-nowrap">
<figure class="music-widget--content">
<header class=" roundme_md">
<h3 class="music-widget--now-playing">{{ loc.musicwidget_now_playing }}</h3>
</header>
<figcaption class="music-widget--content-wrapper">
<h4 class="music-widget--album-title">{{ serverTracks.artist }}</h4>
</figcaption>
<figcaption class="music-widget--content-wrapper">
<p v-if="serverTracks.url" class="music-widget--song-title"><a @click="gaSendEvent('click-track', getTitleAlbum)" :href="serverTracks.url" :title="theTitleAttr" target="_blank">{{ getTitleAlbum }}</a></p>
<p v-else class="music-widget--song-title">{{ getTitleAlbum }}</p>
</figcaption>
<div v-if="volumeSlider" v-for="t in settingsUi.adjusters.music" class="music-widget--volume-control nowrap">
<slider-component :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="volumeControl"></slider-component>
</div>
</figure>
<div class="music-widget--cover-image music-widget--cover-controls roundme_md">
<template v-if="serverTracks.url">
<a v-if="serverTracks.albumArt" @click="gaSendEvent('click-albumArt', getTitleAlbum)" :href="serverTracks.url" :title="theTitleAttr" class="ss-absolute" target="_blank"><img :src="serverTracks.albumArt" class="roundme_md ss-absolute" :alt="serverTracks.album" /></a>
</template>
<template v-else>
<img v-if="serverTracks.albumArt" :src="serverTracks.albumArt" class="ss-absolute roundme_md" alt="Album cover art for" :alt="serverTracks.album" />
</template>
<button v-if="playBtn" @click="playAudio">
<i v-if="playing" class="music-widget--cover-control-icon music-widget--cover-control-pause far fa-pause-circle fa-2x"></i>
<i v-if="!playing" class="music-widget--cover-control-icon music-widget--cover-control-pause far fa-play-circle fa-2x"></i>
</button>
</div>
<div class="music-widget--sponsor">
<a @click="gaSendEvent('click-sponsor', sponsor.name)" v-if="sponsor" :href="sponsor.link" :title="getSponsorTitleAttr" target="_blank"><img :src="getSponsorImg" class="music-widget--sponsor-icon" :alt="sponsor.name" /><span class="hideme">{{sponsor.name}}</span></a>
<button v-if="settings" @click="openSettings" class="music-widget--sponsor--settings-btn"><i class="fas fa-cog"></i><span class="hideme">Music Settings</span></button>
<button class="music-widget--sponsor--settings-btn" @click="toggleMusic"><i class="fas" aria-hidden="true" :class="togglePlayStopIcon"></i><span class="hideme">Music</span></button>
</div>
</div>
</div>
</template>
<script>
const createMusicWidget = templateId => {
return {
template: '#music-widget',
props: ['loc','volumeSlider', 'playBtn', 'settings', 'settingsUi', 'show'],
components: {
'slider-component': comp_settings_adjuster
},
data () {
return vueData.music;
},
mounted () {
this.theAudio = document.getElementById('theAudio');
},
methods: {
loadVolume() {
this.$nextTick(() => {
this.theAudio.volume = Number(this.settingsUi.adjusters.music[0].value);
});
},
getAudioServer() {
if (parsedUrl.dom == 'localhost' || parsedUrl.dom == 'dev' || parsedUrl.dom == 'localshelldev') {
var url = 'uswest2-music.shellshock.io';
}
else {
var server = vueApp.serverList.filter(server => server.locKey === vueApp.currentServerLocKey)[0];
var url = server.subdom.slice(0, -1) + '-music.' + parsedUrl.dom + '.' + parsedUrl.top;
}
this.musicSrc = 'https://' + url + '/shellshock.ogg';
},
setIndex(k) {
this.$nextTick(() => {
this.play();
})
this.currIndex = k;
},
play() {
if (!this.isMusic) return;
this.getAudioServer();
},
playMusic() {
// var audio = this.theAudio;
this.theAudio.src = this.musicSrc;
console.log('Play Music');
clearInterval(this.timer);
this.theAudio.play()
.then( // Returns a Promise
() => { // Success
this.playing = true;
this.loadVolume();
this.duration = this.theAudio.duration;
this.theAudio.addEventListener('stalled', () => this.isMusic = false);
},
() => { // Fail
// What to do... just try again after a few seconds, I guess?
setTimeout(() => this.play(), 2000);
}
);
},
pause() {
this.playing = false;
this.theAudio.pause();
clearInterval(this.timer);
},
/*
next() {
if (this.currIndex < this.tracks.length - 1) {
this.currIndex++;
} else {
this.currIndex = 0;
}
},
prev() {
if (this.currIndex > 0) {
this.currIndex--;
} else {
this.currIndex = this.tracks.length - 1;
}
},
*/
playOnce() {
if (this.playing) return;
return this.play();
},
playAudio() {
if (this.theAudio.paused) {
this.play();
} else {
this.pause();
}
},
openSettings() {
vueApp.showSettingsPopup();
vueApp.onSettingsPopupSwitchTabMisc();
this.gaSendEvent('click', 'widgetOpenSettings');
},
volumeControl(id, value) {
extern.setMusicVolume(value);
vueApp.onSettingsQuickSave();
},
hideMe() {
return this.$refs.id.classList.addClass('fade-out-3');
},
showMe() {
this.show = true;
setTimeout(() => this.show = false, 2000);
},
gaSendEvent(action, label) {
action = action || '';
label = label || '';
return ga('send', 'event', 'music', action, label);
},
toggleMusic() {
if (this.playing) {
this.theAudio.removeEventListener('stalled', () => this.isMusic = false);
this.playing = false;
this.pause();
this.musicSrc = '';
this.theAudio.removeAttribute('src');
extern.setMusicStatus(false);
this.gaSendEvent('toggleMusic', 'off');
return;
}
this.theAudio.src = '';
this.play();
extern.setMusicStatus(true);
this.gaSendEvent('toggleMusic', 'on');
},
changeVolume(val) {
this.theAudio.volume = val;
}
},
watch: {
'currIndex': {
handler() {
this.$nextTick(() => {
this.play();
})
}
},
serverTracks(val) {
let sponsor = this.sponsors.filter(sponsor => sponsor.id === val.sponsor);
this.sponsor = sponsor.length || sponsor.length > 0 ? sponsor[0] : '';
},
musicSrc(val) {
if (val) {
this.playMusic();
}
},
},
computed: {
theTitleAttr() {
return 'Read more about ' + this.serverTracks.title;
},
getTitleAlbum() {
return this.serverTracks.title + ' - ' + this.serverTracks.album;
},
getSponsorImg() {
if (!this.sponsor) {
return;
}
return 'img/sponsor/' + this.sponsor.id + this.sponsor.imageExt;
},
getSponsorTitleAttr() {
return 'See more about our sponsor ' + this.sponsor.name;
},
togglePlayStopIcon() {
return this.playing ? 'fa-stop-circle' : 'fa-play-circle';
},
},
};
};
// Register component globally
Vue.component('music-widget', createMusicWidget('#music-widget'));
</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,
'event-panel': comp_events,
// 'pwa-button': comp_pwa_btn,
},
data: function () {
return vueData;
},
methods: {
playSound (sound) {
BAWK.play(sound);
},
onEquipClicked: function () {
vueApp.switchToEquipUi();
BAWK.play('ui_equip');
},
showSignIn: function () {
extern.showSignInDialog();
vueApp.$refs.firebaseSignInPopup.show();
},
onSignInClicked: function () {
this.showSignIn();
},
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;
this.urlParamSet = this.urlParams ? true : null;
// vueApp.showTitleScreenAd();
vueApp.shellShockUrlParamaterEvents();
},
onPlayerNameChanged: function (newName) {
console.log('play name event handler');
vueApp.setPlayerName(newName);
BAWK.play('ui_onchange');
},
clickEggToPlay() {
play: 'play game',
ga('send', 'event', vueData.googleAnalytics.cat.play, vueData.googleAnalytics.action.eggDollClick);
vueApp.$refs.homeScreen.$refs.playPanel.onPlayButtonClick();
},
},
computed: {
isEggStoreSaleItem() {
return this.eggStoreItems.some( item => item['salePrice'] !== '');
}
}
};
</script><script id="equip-screen-template" type="text/x-template">
<div>
<div id="equip_wrapper">
<account-panel id="account_panel" ref="accountPanelEquip" :loc="loc" :eggs="eggs" :show-corner-buttons="ui.showCornerButtons" :ui="ui" :show-bottom="false" :is-anonymous="isAnonymous" :isEggStoreSale="isEggStoreSaleItem"></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" :disabled="!accountSettled" :class="getButtonToggleClass(equip.equipModes.shop)" @click="switchToShop">{{ loc.eq_shop }}</i></button>
</div>
<div id="equip_purchase_top" class="equip_purchase_top">
<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" ref="weapon_select":current-class="classIdx" :loc="loc" @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 v-if="!isBuyingItemPrem" src="img/ico_goldenEgg.png" class="egg_icon"/>
<i v-else class="fas fa-dollar-sign"></i>
<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();
BAWK.play('ui_chicken');
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 v-if="!isPremium" src="img/ico_goldenEgg.png">
<i v-else class="fas fa-dollar-sign"></i>
{{ 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 () {
if (this.isPremium) {
return vueApp.showPopupEggStoreSingle(this.item.sku);
}
this.$emit('buy-item-clicked', this.item);
}
},
computed: {
isPremium() {
return this.item.unlock === 'premium';
},
}
};
</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 v-if="accountSettled" class="margins_sm">{{ loc[categoryLocKey] }}</h3>
<div v-if="accountSettled" 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 id="items-account-not-loaded" v-show="!accountSettled" class="center_cont">
<h3>{{loc.signin_auth_title}}</h3>
<p>{{loc.signin_auth_msg}}</p>
</div>
</div>
</script>
<script>
var comp_item_grid = {
template: '#item-grid-template',
components: { 'item': comp_item },
props: ['items', 'selectedItem', 'gridClass', 'categoryLocKey', 'inShop'],
data() {
return vueData;
},
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');
BAWK.play('ui_playconfirm');
}
},
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.showTitleScreenAd();
vueApp.switchToHomeUi();
} else {
extern.closeEquipInGame();
vueApp.switchToGameUi();
vueApp.showGameMenu();
vueApp.showRespawnDisplayAd();
}
BAWK.play('ui_popupclose');
},
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();
}
BAWK.play('ui_click');
},
onTaggedItemsClicked: function () {
this.showTaggedItems(this.equip.specialItemsTag);
this.selectFirstItemInShop();
BAWK.play('ui_click');
},
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);
},
showSelectedTagItems(tag) {
this.equip.selectedItemType = 'tagged';
if (this.equip.mode === this.equip.equipModes.inventory) {
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();
BAWK.play('ui_toggletab');
// vueApp.histPushState({game: this.ui.screens.equip}, 'Shellshockers equipment inventory', '?equip=inventory');
},
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 () {
if (!this.accountSettled) {
return;
}
this.equip.mode = this.equip.equipModes.shop;
this.showItemsAfterEquipModeSwitch();
this.selectFirstItemInShop();
vueApp.conditionalAnonWarningCall();
BAWK.play('ui_toggletab');
// vueApp.histPushState({game: this.ui.screens.equip}, 'Shellshockers equipment shop', '?equip=shop');
},
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);
if (extern.inGame && this.ui.showScreen !== this.ui.screens.equip) {
this.equip.showingWeaponType = ItemType.Primary;
this.poseEquippedItems();
extern.closeEquipInGame();
}
},
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);
BAWK.play('ui_click');
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":
case "premium":
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;
BAWK.play('ui_popupopen');
},
onBuyItemConfirm: function () {
if (this.equip.buyingItem.unlock === 'premium') {
extern.buyProductForMoney(this.equip.buyingItem.sku);
return;
} else {
extern.api_buy(this.equip.buyingItem, this.boughtItemSuccess, this.boughtItemFailed);
}
BAWK.play('ui_playconfirm');
},
boughtItemSuccess: function () {
this.equip.selectedItem = this.equip.buyingItem;
ga('send', 'event', {
eventCategory: this.googleAnalytics.cat.itemShop,
eventAction: this.googleAnalytics.action.shopItemPopupBuy,
eventLabel: this.equip.buyingItem.name,
eventValue: this.equip.selectedItem.price
});
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');
BAWK.play('ui_reset');
},
onRedeemClick: function () {
this.$refs.redeemCodePopup.code = '';
this.$refs.redeemCodePopup.toggle();
BAWK.play('ui_popupopen');
},
onRedeemCodeConfirm: function () {
extern.api_redeem(this.equip.redeemCodePopup.code, this.redeemCodeSuccess, this.redeemCodeFailed);
BAWK.play('ui_playconfirm');
},
redeemCodeSuccess: function (eggs, items) {
this.populateItemGridWithType(this.equip.selectedItemType);
this.giveStuffPopup.eggs = eggs;
this.giveStuffPopup.items = items;
vueApp.showGiveStuffPopup('p_give_stuff_title', eggs, items);
let itemString = '';
this.giveStuffPopup.items.forEach(item => itemString += item.name);
ga('send', 'event', {
eventCategory: this.googleAnalytics.cat.redeem,
eventAction: this.googleAnalytics.action.redeemed,
eventLabel: `${itemString ? itemString : ''} ${this.giveStuffPopup.eggs ? this.giveStuffPopup.eggs + 'eggs' : ''}`
});
},
redeemCodeFailed: function () {
vueApp.showGenericPopup('p_redeem_error_title', 'p_redeem_error_content', 'ok');
BAWK.play('ui_reset');
},
onPhysicalUnlockConfirm: function () {
window.open(this.equip.physicalUnlockPopup.item.item_data.physicalItemStoreURL, '_blank');
},
onColorChanged: function (colorIdx) {
this.equip.colorIdx = colorIdx;
extern.setShellColor(this.equip.colorIdx);
BAWK.play('ui_onchange');
},
onSwitchToShopClicked: function () {
this.switchToShop();
}
},
computed: {
isInShop: function () {
return (this.equip.mode === this.equip.equipModes.shop);
},
getGridClass: function () {
return this.isInShop ? '' : 'equip_grid_short';
},
isEggStoreSaleItem() {
return this.eggStoreItems.some( item => item['salePrice'] !== '');
},
isBuyingItemPrem() {
if (!this.equip.buyingItem) {
return;
}
return this.equip.buyingItem.unlock === 'premium';
}
}
};
</script><script id="game-screen-template" type="text/x-template">
<div>
<event-panel :show-soon="false" :show-ui="ui.showCornerButtons"></event-panel>
<account-panel id="game_account_panel" ref="accountPanelGame" :loc="loc" :eggs="eggs" :show-bottom="false" :show-corner-buttons="ui.showCornerButtons" :ui="ui" :isEggStoreSale="isEggStoreSaleItem"></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 normal"></div>
<div id="crosshair1" class="crosshair normal"></div>
<div id="crosshair2" class="crosshair normal"></div>
<div id="crosshair3" class="crosshair normal"></div>
</div>
<div id="shotReticleContainer">
<div id="shotBracket0" class="shotReticle border normal"></div>
<div id="shotBracket1" class="shotReticle border normal"></div>
<div id="shotBracket2" class="shotReticle fill normal"></div>
<div id="shotBracket3" class="shotReticle fill normal"></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 v-show="(((doubleEggWeekend || doubleEggWeekendSoon) && !ui.showCornerButtons) || (!doubleEggWeekend && !doubleEggWeekendSoon))" id="best_streak_container">
<!--<h3>{{ loc.ui_game_beststreak }}</h3>-->
<h1 id="bestStreak">x0</h1>
</div>
<div id="shellStreakContainer">
<h1 id="shellStreakCaption"></h1>
<h1 id="shellStreakMessage" class="disappear"></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="healthContainer">
<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>
<!-- Hard Boiled -->
<div id="hardBoiledContainer">
<div id="hardBoiledShieldContainer">
<img class="hardBoiledShield" src="img/hardBoiledEmpty.png">
<img class="hardBoiledShield" id="hardBoiledShieldFill" src="img/hardBoiledFilled.png">
</div>
<div id="hardBoiledValue">100</div>
</div>
<!-- EggBreaker Shellstreak -->
<div id="eggBreakerContainer" class="off">
<img id="eggBreakerIcon" src="img/ico_eggBreaker.png" />
<div id="eggBreakerTimer">15</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 v-bind:placeholder="loc.ingame_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 class="player__container">
<!-- Player List -->
<div id="playerSlot" class="playerSlot" style="display: none">
<div>
<span></span> <!-- Name -->
<span></span> <!-- Score -->
</div>
<div style="display: block;"></div> <!-- Icons -->
</div>
<div id="playerList"></div>
</div>
<!-- end .player__container -->
<div id="inGameScaler">
<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 class="box_blue2 roundme_sm">
<div id="pausePopupInnards" class="roundme_sm f_row">
<div id="pauseButtons" class="f_col pause-btn-group">
<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>
<button v-if="!delayTheCracking && !isRespawning" class="ss_button btn_red bevel_red btn_sm" disabled="disabled"><i class="fas fa-eye"></i> {{ loc.ui_game_get_ready }}</button>
<button v-if="delayTheCracking" v-show="!isRespawning" @click="onSpectateClicked()" class="ss_button btn_blue bevel_blue btn_sm" :disabled="isRespawning"><i class="fas fa-eye"></i> {{ loc.p_pause_spectate }}</button>
<music-widget ref="gameScreenMusic" :loc="loc" :settings-ui="settingsUi" :settings="true" :volumeSlider="false" :show="isPaused && showMusicWidget"></music-widget>
</div>
<!-- #pauseButtons -->
<div id="popupTipDay" class="roundme_sm flex-auto">
<div v-if="isPoki && pokiRewardReady" class="poki-reward-container">
<button class="ss_button btn_blue bevel_blue btn_reward pure-wiggle" @click="earnInGameReward"><img src="img/ico_goldenEgg.png" class="egg_icon">Watch Video for 100 Golden Eggs!</button>
</div>
<!-- .poki-reward-container -->
<div id="btn_horizontal" class="pause-popup--btn-group">
<header class="weapon-select weapon-select--title pause-bg roundme_sm">
<h1>{{loc.p_weapon_title}}</h1>
</header>
<div class="pause-bg roundme_sm">
<weapon-select-panel ref="weaponSelect" id="weapon_select" :loc="loc" :current-class="classIdx" @changed-class="pauseWeaponSelect"></weapon-select-panel>
</div>
<!-- .pause-bg -->
</div>
<!-- .pause-popup--btn-group -->
<div id="game-play-switch" class="paused-game-cotrols roundme_sm f_row">
<div v-if="delayTheCracking" class="switch-teams-btn">
<button v-show="isTeamGame" @click="onSwitchTeamClicked" class="ss_button btn__team_switch" :class="teamColorCss"><i class="fa fa-flag"></i> {{ teamName }}</button>
</div>
<!-- .switch-teams-btn -->
<div class="pause-popup--btn-group f-grow-full">
<button v-if="!delayTheCracking && !isRespawning" class="btn_big btn_wfull ss_button btn_red bevel_red" disabled="disabled">{{ loc.ui_game_get_ready }}</button>
<button v-if="delayTheCracking" class="btn_big btn_wfull ss_button btn_red bevel_red" v-show="isRespawning" :disabled="isRespawning">{{ game.respawnTime }}</button>
<button v-if="delayTheCracking" v-show="!isRespawning" @click="onPlayClicked()" class="btn-respawn btn_big btn_wfull ss_button btn_yolk bevel_yolk" :disabled="isRespawning"><i class="fa fa-play"></i> {{ loc.p_pause_play }}</span></button>
<!-- .pause-popup--btn-group -->
</div>
<!-- .w-shrinkauto -->
</div>
<!-- #game-play-switch -->
</div>
<!-- #popupTipDay -->
</div>
<!-- #pausePopupInnards -->
</div>
</template>
</large-popup>
<!-- <div id="pauseAdPlacement" ref="pauseAdPlacement"></div> -->
<div class="respawn-container" v-show="isPaused">
<display-ad id="shellshockers_respawn_banner" ref="respawnDisplayAd" class="pauseAdPlacement" :adUnit="adUnits.display.respawn" pokiAdSize="728x90"></display-ad>
</div>
</div>
<!-- .pause-popup--container -->
<!-- <div id="testbaby"></div> -->
</div>
<!-- end #inGameScaler -->
<div class="in-game-widgets">
<music-widget ref="musicWidgetinGame" :loc="loc" :settings-ui="settingsUi" :show="showIngameWidget"></music-widget>
</div>
{{showIngameWidget}}
</div>
</script>
<script>
var comp_game_screen = {
template: '#game-screen-template',
components: {
'account-panel': comp_account_panel,
// 'event-panel': comp_events,
'weapon-select-panel': comp_weapon_select_panel,
// 'music-widget': comp_music_widget,
'event-panel': comp_events,
'weapon-select-panel': comp_weapon_select_panel,
},
data: function () {
return vueData;
},
created: function () {
this.isPoki = ! extern.pokiInitialized() ? extern.pokiInitialized() : extern.isPokiSDK();
},
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();
this.isPaused = true;
setTimeout(() => vueApp.disableRespawnButton(false), 500);
vueData.ui.showCornerButtons = true;
vueApp.gameUiAddClassForNoScroll();
addEventListener('gamepadbuttondown', this.onControllerButton);
},
delayGameMenuPlayButtons() {
setTimeout(() => {
this.delayTheCracking = true;
}, 3000);
},
hideGameMenu: function () {
if (!extern.inGame) {
return;
}
this.$refs.pausePopup.hide();
this.$refs.respawnDisplayAd.hide();
this.isPaused = false;
vueApp.gameUiAddClassForNoScroll();
removeEventListener('gamepadbuttondown', this.onControllerButton);
},
onHomeClicked: function () {
this.hideGameMenu();
this.$refs.leaveGameConfirmPopup.show();
BAWK.play('ui_click');
},
onLeaveGameConfirm: function () {
this.leaveGame();
this.delayTheCracking = false;
},
onLeaveGameCancel: function () {
this.showGameMenu();
},
leaveGame: function () {
// clientGame.js manipulates chickenBadge element directly to hide/show it
vueApp.disablePlayButton(false);
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.showTitleScreenAd();
vueApp.switchToHomeUi();
},
onHelpClicked: function () {
this.hideGameMenu();
vueApp.showHelpPopup();
BAWK.play('ui_popupopen');
},
onShareLinkClicked: function () {
extern.inviteFriends();
BAWK.play('ui_popupopen');
},
onSettingsClicked: function () {
this.hideGameMenu();
vueApp.showSettingsPopup();
BAWK.play('ui_popupopen');
},
onShareLinkConfirm: function () {
extern.copyFriendCode(this.$refs.shareLinkUrl);
},
onShareLinkClosed: function () {
this.showGameMenu();
},
onEquipClicked: function () {
this.hideGameMenu();
extern.openEquipInGame();
vueApp.switchToEquipUi();
BAWK.play('ui_equip');
},
onSwitchTeamClicked: function () {
this.hideGameMenu();
BAWK.play('ui_popupopen');
this.$refs.switchTeamPopup.show();
},
onSwitchTeamCancel: function () {
this.showGameMenu();
},
onSwitchTeamConfirm: function () {
extern.switchTeam();
},
onControllerButton: function (e) {
switch (e.detail) {
case '9':
if (document.hasFocus() && !this.isRespawning && this.delayTheCracking) {
this.onPlayClicked();
}
break;
case '4':
case '6':
case '14':
vueData.classIdx = Math.max(0, vueData.classIdx - 1);
this.$refs.weaponSelect.selectClass(vueData.classIdx);
break;
case '5':
case '7':
case '15':
vueData.classIdx = Math.min(5, vueData.classIdx + 1);
this.$refs.weaponSelect.selectClass(vueData.classIdx);
break;
}
},
onPlayClicked: function () {
vueApp.disableRespawnButton(true);
vueData.ui.showCornerButtons = false;
extern.respawn();
this.isPaused = false;
BAWK.play('ui_playconfirm');
},
onSpectateClicked: function () {
this.hideGameMenu();
vueData.ui.showCornerButtons = false;
extern.enterSpectatorMode();
vueApp.hideRespawnDisplayAd();
BAWK.play('ui_playconfirm');
},
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';
},
earnInGameReward() {
this.hideGameMenu();
vueApp.setDarkOverlay(true);
this.pokiRewardReady = false;
this.isPokiNewRewardTimer = false;
extern.api_inGameReward(this.inGameRewardSuccessCallback, this.inGameRewardFailedCallback, this.rewardReachedDailyLimits);
extern.setVolume(0);
},
inGameRewardSuccessCallback() {
extern.pokiRewardedBreak(this.inGameRewardIsGranted, this.inGameRewardFailedCallback);
},
inGameRewardIsGranted(rewardValue) {
console.log('inGameRewardSuccessCallback');
this.isPokiNewRewardTimer = true;
vueApp.showGiveStuffPopup('reward_title', rewardValue, '');
ga('send', 'event', 'Poki', 'Rewarded Video', 'Reward Success', this.pokiRewNum);
this.pokiRewNum ++;
},
inGameRewardFailedCallback() {
vueApp.showGenericPopup('p_redeem_error_title', 'in_game_reward_try_again', 'ok');
this.isPokiNewRewardTimer = false;
ga('send', 'event', 'Poki', 'Rewarded Video', 'Failed');
},
rewardReachedDailyLimits() {
vueApp.showGenericPopup('in_game_reward_title', 'in_game_reward_try_again', 'ok');
this.isPokiNewRewardTimer = false;
localStore.setItem('inGameRewardLimitDate', Date.now());
extern.setVolume();
ga('send', 'event', 'Poki', 'Rewarded Video', 'Reached Daily Limit');
},
pokiTimers(value, milliseconds) {
let pokiSetTimer;
if (value === false) {
clearTimeout(pokiSetTimer);
console.log('cancelTimer');
return;
}
pokiSetTimer = setTimeout(() => this.pokiRewardReady = true, milliseconds);
},
pauseWeaponSelect() {
vueApp.$refs.equipScreen.onChangedClass();
},
songHasChanged() {
setTimeout(() => this.songChanged = false , 2000);
}
},
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;
},
showIngameWidget() {
if (!this.isPaused && this.songChanged) {
this.songHasChanged();
return true;
}
return false;
},
showMusicWidget() {
return this.ui.showScreen === 2;
},
isEggStoreSaleItem() {
return this.eggStoreItems.some( item => item['salePrice'] !== '' && this.ui.showCornerButtons);
}
},
watch: {
isPokiGameLoad(value) {
this.pokiTimers(value, this.videoRewardTimers.initial);
// this.pokiTimers(value, 300);
},
isPokiNewRewardTimer(value) {
this.pokiTimers(value, this.videoRewardTimers.primary);
// this.pokiTimers(value, 300);
},
}
};
</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,
'egg-store-item': comp_store_item,
},
data: vueData,
createdTime: null,
mountedTime: null,
fullyRenderedTime: null,
multisizeAdTag: null,
created () {
console.log('Vue instance created');
createdTime = performance.now();
this.currentLanguageCode = languageCode;
this.urlParams = parsedUrl.query.open ? parsedUrl.query.open : null;
},
mounted () {
console.log('Vue instance mounted');
mountedTime = performance.now();
console.log('create -> mount time (ms): ' + (mountedTime - createdTime));
this.currentGameType = extern.gameType;
// 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;
// vueApp.getNuggetTimer();
this.showSpinner('ui_game_loading', 'ui_game_waitforit');
// this.histPushState({game: this.ui.screens.home}, 'Shellshockers home', '?home');
//this.playMusic();
extern.continueStartup();
this.fetchSponors();
});
},
methods: {
getCanvas: function () {
return this.$refs.canvas;
},
playMusic: function () {
myAudio = new Audio('./sound/theme');
// Uncomment for looping.
// myAudio.addEventListener('ended', function() {
// this.currentTime = 0;
// this.play();
// }, false);
myAudio.volume = this.volume;
myAudio.play();
},
changeLanguage: function (languageCode) {
extern.getLanguageData(languageCode, this.setLocData);
},
setLocData: function (languageCode, newLocData) {
this.currentLanguageCode = getStoredString('languageSelected', null) ? localStore.getItem('languageSelected') : 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();
},
onSettingsPopupSwitchTabMisc: function () {
this.$refs.settings.switchTab('misc_button');
},
onSettingsX: function () {
this.$refs.settings.applyOriginalSettings();
this.$refs.settings.cancelLanguageSelect();
},
onSettingsQuickSave() {
this.$refs.settings.quickSave();
},
onNoAnonPopupConfirm: function () {
ga('send', 'event', this.googleAnalytics.cat.playerStats, this.googleAnalytics.action.denyAnonUserPopup, this.googleAnalytics.label.signInClick);
this.showFirebaseSignIn();
},
onSharedPopupClosed: function () {
// If in-game, show game menu after closing the popup
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();
},
showUnsupportedPlatformPopup: function (contentLocKey) {
this.ui.showScreen = -1;
this.unsupportedPlatformPopup.contentLocKey = contentLocKey;
this.$refs.unsupportedPlatformPopup.show();
},
showMissingFeaturesPopup: function () {
this.ui.showScreen = -1;
this.$refs.missingFeaturesPopup.show();
},
showFirebaseSignIn: function () {
this.$refs.homeScreen.showSignIn();
},
hideFirebaseSignIn: function () {
this.$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.$nextTick(() => {
this.hideGameMenu();
this.$refs.eggStorePopup.show();
ga('send', 'event', this.googleAnalytics.cat.itemShop, this.googleAnalytics.action.shopItemNeedMoreEggsPopup, this.googleAnalytics.label.getMoreEggs);
});
},
showPopupEggStoreSingle(sku) {
if (!sku) return; console.log('No sku for popup');
const hasSku = (element) => element.sku === sku;
if (!this.eggStoreItems.some(hasSku)) {
vueApp.showGenericPopup("uh_oh", "p_egg_shop_no_item_desc", "ok");
return;
}
this.eggStorePopupSku = sku;
return this.$refs.popupEggStoreSingle.show();
},
hideEggStorePopup: function () {
this.$refs.eggStorePopup.hide();
},
showChangelogPopup: function () {
this.$refs.changelogPopup.show();
},
hideChangelogPopup: function () {
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);
},
showPrivateGamePopup() {
this.$refs.homeScreen.$refs.playPanel.$refs.createPrivateGamePopup.toggle();
},
switchToHomeUi: function () {
this.ui.showScreen = this.ui.screens.home;
// vueApp.showTitleScreenAd();
// this.histPushState({game: this.ui.screens.home}, 'Shellshockers home', '?home');
this.gameUiRemoveClassForNoScroll();
},
switchToEquipUi: function () {
console.log('switchToEquipUi called');
this.$refs.equipScreen.setup();
this.$refs.equipScreen.switchToInventory();
this.ui.showScreen = this.ui.screens.equip;
vueApp.hideTitleScreenAd();
},
switchToGameUi: function (isGameOwner) {
this.ui.showScreen = this.ui.screens.game;
this.game.isGameOwner = isGameOwner;
},
gameUiAddClassForNoScroll() {
let html = document.getElementsByTagName("html")[0];
html.classList.add('noScrollIngame');
},
gameUiRemoveClassForNoScroll() {
let html = document.getElementsByTagName("html")[0];
html.classList.remove('noScrollIngame');
},
switchToGameUiQuickPlay(isGameOwner) {
this.ui.showScreen = this.ui.screens.game;
this.game.isGameOwner = isGameOwner;
this.ui.showCornerButtons = false;
vueApp.hideTitleScreenAd();
this.gameUiAddClassForNoScroll();
},
showGameMenu: function () {
this.hideSpinner();
this.$refs.gameScreen.showGameMenu();
// this.histPushState({game: this.ui.screens.game}, 'Shellshockers game menu', '?game=menu');
},
hideGameMenu: function () {
this.$refs.gameScreen.hideGameMenu();
// this.histPushState({game: this.ui.screens.game}, 'Shellshockers in game', '?game=play');
},
onMiniGameCompleted: function () {
this.$refs.homeScreen.onMiniGameCompleted();
},
setShellColor: function (colorIdx) {
this.equip.colorIdx = colorIdx;
},
setAccountUpgraded: function (upgraded, endDate) {
this.isUpgraded = upgraded;
this.equip.extraColorsLocked = !this.isUpgraded;
this.nugStart = endDate;
// vueApp.getNuggetTimer();
},
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.accountSettled = true;
if (vueApp.$refs.firebaseSignInPopup.isShowing) this.hideFirebaseSignIn();
},
showItemOnEquipScreen: function (item) {
this.switchToEquipUi();
this.$refs.equipScreen.autoSelectItem(item);
},
showTaggedItemsOnEquipScreen: function (tag) {
this.switchToEquipUi();
this.$refs.equipScreen.showTaggedItems(tag);
},
showSelectedTaggedItemsOnEquipScreen: function (tag) {
this.switchToEquipUi();
this.$refs.equipScreen.showSelectedTagItems(tag);
},
useHouseAdSmall: function (smallHouseAd) {
this.ui.houseAds.small = smallHouseAd;
},
useHouseAdBig: function (bigHouseAd) {
this.ui.houseAds.big = bigHouseAd;
},
denyAnonUser: function () {
ga('send', 'event', vueApp.googleAnalytics.cat.playerStats, vueApp.googleAnalytics.action.denyAnonUserPopup);
if (extern.inGame) {
this.hideGameMenu();
}
this.$refs.noAnonPopup.show();
},
showGdprNotification: 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);
BAWK.play('ui_onchange');
},
targetedAdsChanged: function () {
extern.setTargetedAds(this.showTargetedAds);
BAWK.play('ui_onchange');
},
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();
this.isBuyNugget = true;
console.log('showNuggetPopup()');
},
hideNuggetPopup: function () {
this.$refs.nuggetPopup.hide();
this.$refs.chickenNugget.unloadMiniGame();
console.log('Hide nugget');
},
loadNuggetVideo() {
this.hideGameMenu();
extern.startChickenNugget();
BAWK.play('ui_playconfirm');
},
getNuggetTimer() {
return;
this.$refs.homeScreen.$refs.chickenPanel.setupNuggetTimer();
},
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();
},
onSignInCancelClicked: function () {
vueApp.$refs.firebaseSignInPopup.hide();
BAWK.play('ui_popupclose');
},
anonWarningPopupCancel: function() {
let anonWarnConfrimed = localStore.getItem('anonWarningConfirmed');
this.urlParamSet = this.urlParams ? true : null;
this.shellShockUrlParamaterEvents();
ga('send', 'event', this.googleAnalytics.cat.playerStats, this.googleAnalytics.action.anonymousPopupOpenAuto, this.googleAnalytics.label.understood);
return anonWarnConfrimed === null && localStore.setItem('anonWarningConfirmed', true);
},
anonWarningPopupConfrim() {
let anonWarnConfrimed = localStore.getItem('anonWarningConfirmed');
anonWarnConfrimed === null && localStore.setItem('anonWarningConfirmed', true);
ga('send', 'event', this.googleAnalytics.cat.playerStats, this.googleAnalytics.action.anonymousPopupOpenAuto, this.googleAnalytics.label.signInClick);
extern.showSignInDialog();
this.urlParamSet = false;
vueApp.$refs.firebaseSignInPopup.show();
},
conditionalAnonWarningCall: function() {
let anonWarnConfrimed = localStore.getItem('anonWarningConfirmed');
if ( ! hasValue(anonWarnConfrimed) && this.isAnonymous) {
vueApp.showAttentionPopup();
ga('send', 'event', this.googleAnalytics.cat.playerStats, this.googleAnalytics.action.anonymousPopupOpenAuto);
}
},
needMoreEggsPopupCall: function() {
ga('send', 'event', this.googleAnalytics.cat.itemShop, this.googleAnalytics.action.shopItemNeedMoreEggsPopup);
this.$refs.needMoreEggsPopup.show();
},
/**
* Not 100 % certain this should live in vue but here it is.
* Add the ability to use url paramaters to trigger events in the game.
* e.g. shellshock.io/?open=eggStore&type=Hat&item=1111 will open the spiderman hat item.
* Called in the extern closure under gameApp.js => afterGameReady()
*/
shellShockUrlParamaterEvents() {
// VUE next tick https://vuejs.org/v2/api/#Vue-nextTick
this.$nextTick( ()=> {
this.doSsUlrParams();
});
},
doSsUlrParams() {
if ( ! this.urlParams) {
return;
}
console.log(hasValue(this.isAnonymous));
if (hasValue(this.ui.houseAds.big)) {
this.urlParamSet = false;
return;
} else if (this.isAnonymous && ! hasValue(localStore.getItem('anonWarningConfirmed'))) {
this.urlParamSet = false;
console.log('Almost there!');
this.conditionalAnonWarningCall();
return;
}
console.log('Passed Popup gate');
switch (this.urlParams) {
case 'eggStore' :
// Opens the purchase egg store popup
this.showEggStorePopup();
break;
case 'goldenChicken' :
// Opens the golden chicken popup
vueApp.$refs.goldChickenPopup.show();
break;
case 'twoTimesTheEggs' :
// Opens the chicken nugget video
extern.startChickenNugget();
BAWK.play('ui_playconfirm');
break;
case 'itemShop' :
// Opens shop
// Some opions are /?open=itemShop
// /?open=itemShop&type=Hat Opens hat store
// /?open=itemShop&type=Hat&item=1111 opens hat store and then selects item
// /?open=itemShop&type=Hat&item=1111&openBuyNow=1 -opens hat store, selects item and then opens items popup
//?open=itemShop&type=Primary&gunClass=Soldier&item=3113
this.eggStoreUrlParams();
break;
case 'redeem' :
vueApp.switchToEquipUi();
BAWK.play('ui_popupopen');
this.$refs.equipScreen.$refs.redeemCodePopup.show();
if ('code' in parsedUrl.query) this.equip.redeemCodePopup.code = parsedUrl.query.code;
break;
case 'faq' :
this.showHelpPopup();
break;
case 'taggedItems' :
this.openSpecialTagItemsTab();
break;
case 'privateGame' :
this.showPrivateGamePopup();
break;
default:
null;
};
},
// @param ITEMIDPARAM - number - Item id
// @param TYPEPARAM - string - item type such as Hat
// @param GUNCLASS - string - gun type such as Soldier
// @param BUYNOWPOPUP - bool 1 or 0 will open item popup
// @param ITEMTYPES - array - item types to verify against
// @param GUNCLASSTYPES - array - gun classes to verify against
// @param HASGUNTYPE - sting - returns true if class in GUNCLASSTYPES
// @param HASITEMTYPE - string - returns true if item type in ITEMTYPES
// @param DELAYTIMER - - number - sorta need to short circit the whole thing since vue loads a bit slowly at times.
eggStoreUrlParams() {
setTimeout(() => {
const ITEMIDPARAM = parsedUrl.query.item,
TYPEPARAM = parsedUrl.query.itemType,
GUNCLASS = parsedUrl.query.gunClass,
BUYNOWPOPUP = Boolean(parsedUrl.query.openBuyNow),
ITEMTYPES = [1,2,3,4],
GUNCLASSTYPES = [0,1,2,3,4,5],
HASGUNTYPE = GUNCLASSTYPES.includes(GUNCLASS),
HASITEMTYPE = ITEMTYPES.includes(TYPEPARAM);
if (ITEMIDPARAM) {
const IDISNUMBER = parseInt(ITEMIDPARAM);
let item = extern.catalog.findItemById(IDISNUMBER);
if (item.is_available === false) {
vueApp.showGenericPopup("uh_oh", "no_anon_title", "ok")
return;
}
let isItemOwned = false;
this.switchToEquipUi();
if (extern.isItemOwned(item)) {
isItemOwned = true;
this.$refs.equipScreen.switchToInventory();
vueApp.showGenericPopup("uh_oh", "p_buy_owned_title", "ok")
} else {
this.$refs.equipScreen.autoSelectItem(item);
if (BUYNOWPOPUP === true) {
console.log('Will it open?');
vueApp.$refs.equipScreen.onBuyItemClicked();
return;
}
}
} else {
this.openEquipUISwitchToShop();
if (HASGUNTYPE) {
vueApp.$refs.equipScreen.switchItemType(ItemType['Primary']);
vueApp.$refs.equipScreen.$refs.weapon_select.selectClass(GUNCLASS);
console.log('Has GUN');
} else if (HASITEMTYPE) {
console.log('OPEN item');
vueApp.$refs.equipScreen.switchItemType(TYPEPARAM);
}
}
}, 45);
},
openSpecialTagItemsTab() {
let tag = parsedUrl.query.tag ? parsedUrl.query.tag : null;
vueApp.showSelectedTaggedItemsOnEquipScreen(tag);
},
openEquipUISwitchToShop() {
vueApp.switchToEquipUi();
vueApp.$refs.equipScreen.switchToShop();
},
delayInGamePlayButtons() {
vueApp.$refs.gameScreen.delayGameMenuPlayButtons();
},
//Call/hide display ads
hideRespawnDisplayAd() {
this.$refs.gameScreen.$refs.respawnDisplayAd.hide();
},
showRespawnDisplayAd() {
console.log('showRespawnDisplayAd');
this.$refs.gameScreen.$refs.respawnDisplayAd.show();
},
hideLoadingScreenAd() {
this.$refs.spinnerOverlay.$refs.loadingScreenDisplayAd.hide()
},
showLoadingScreenAd() {
this.$refs.spinnerOverlay.$refs.loadingScreenDisplayAd.show();
// this.histPushState({game: 3}, 'Shellshockers Loading display ad', '?loadingAd=true');
},
displayAdEventObject(event) {
let object = event;
this.displayAdObject = object.size[0];
},
showTitleScreenAd() {
console.log('showTitleScreenAd');
this.$refs.homeScreen.$refs.titleScreenDisplayAdd.show();
},
hideTitleScreenAd() {
this.$refs.homeScreen.$refs.titleScreenDisplayAdd.hide();
},
toggleTitleScreenAd() {
console.log('toggle');
this.$refs.homeScreen.$refs.titleScreenDisplayAdd.toggleAd();
},
scrollToTop() {
let position =
document.body.scrollTop || document.documentElement.scrollTop,
scrollAnimation;
if (position) {
window.scrollBy(0, -Math.max(1, Math.floor(position / 10)));
scrollAnimation = setTimeout(this.scrollToTop, 10);
} else clearTimeout(scrollAnimation);
},
externPlayObject(playType, gameType, playerName, mapIdx, joinCode) {
return extern.play({playType, gameType, playerName, mapIdx, joinCode});
},
pleaseWaitPopup() {
vueApp.showGenericPopup("signin_auth_title", "signin_auth_msg");
},
isPlayingPoki() {
console.log('ispoki called');
this.ready = true;
return;
},
histPushState(obj, title, param) {
return history.pushState(obj, title, param);
},
disablePlayButton(val) {
return document.querySelector('.play-button').disabled = val;
},
disableRespawnButton(val) {
return document.querySelector('.btn-respawn') ? document.querySelector('.btn-respawn').disabled = val : '';
},
disaplyAdEventObject(event) {
let object = event;
this.displayAdObject = object.size[0];
},
adBlockerPopupToggle() {
return vueApp.$refs.adBlockerPopup.toggle();
},
musicPlayOnce() {
return setTimeout(() => this.$refs.gameScreen.$refs.gameScreenMusic.playOnce(), 2000);
},
musicPause() {
this.$refs.gameScreen.$refs.gameScreenMusic.pause();
},
musicVolumeControl(value) {
this.settingsUi.adjusters.music[0].value = Number(value);
this.$refs.gameScreen.$refs.gameScreenMusic.loadVolume();
},
toggleMusic() {
this.$refs.gameScreen.$refs.gameScreenMusic.toggleMusic();
},
musicWidget(val) {
this.music.isMusic = val;
},
fetchSponors() {
fetch(this.music.musicJson)
.then((response) => response.json())
.then((sponsors) => this.music.sponsors = sponsors)
.catch((error) => console.log('Sponsors fetch error', error));
},
pwaPopup() {
return this.$refs.pwaPopup.show();
},
pwaBtnClick() {
// Track the click
ga('send', 'event', 'pwa', 'button', 'click');
//close popup
this.$refs.pwaPopup.hide();
// Get the event
this.pwaDeferEvent = extern.getPwaEvent;
if (!this.pwaDeferEvent) {
return;
}
this.pwaDeferEvent.prompt();
this.pwaDeferEvent.userChoice
.then((choiceResult) => {
if (choiceResult.outcome === 'accepted') {
console.log('User accepted the A2HS prompt');
} else {
console.log('User dismissed the A2HS prompt');
}
ga('send', 'event', 'pwa', 'a2hs', choiceResult.outcome);
this.pwaDeferEvent = null;
});
this.pwaDeferEvent = '';
}
},
computed: {
classObject() {
return {
'playing-poki': this.isPoki
}
},
},
watch: {
isPaused(val) {
if (!val)
return this.hideRespawnDisplayAd();
},
accountSettled(val) {
if (val) {
}
}
}
});
}
</script>
</body>
</html>