/*
* Copyright 2010 by Dan Fabulich.
*
* Dan Fabulich licenses this file to you under the
* ChoiceScript License, Version 1.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.choiceofgames.com/LICENSE-1.0.txt
*
* See the License for the specific language governing
* permissions and limitations under the License.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied.
*/
function printx(msg, parent) {
if (msg === null || msg === undefined || msg === "") return;
if (!parent) parent = document.getElementById('text');
if (msg == " ") {
// IE7 doesn't like innerHTML that's nothing but " "
parent.appendChild(document.createTextNode(" "));
return;
}
msg = (msg+"").replace(/&/g, '&')
.replace(//g, '>')
.replace(/"/g, '"')
.replace(/\[n\/\]/g, '
')
.replace(/\[b\]/g, '')
.replace(/\[\/b\]/g, '')
.replace(/\[i\]/g, '')
.replace(/\[\/i\]/g, '');
var frag = document.createDocumentFragment();
temp = document.createElement('div');
temp.innerHTML = msg;
while (temp.firstChild) {
frag.appendChild(temp.firstChild);
}
parent.appendChild(frag);
}
function println(msg, parent) {
if (!parent) parent = document.getElementById('text');
printx(msg, parent);
var br = window.document.createElement("br");
parent.appendChild(br);
}
function showStats() {
if (document.getElementById('loading')) return;
setButtonTitles();
if (window.stats.scene.secondaryMode == "stats") {
clearScreen(loadAndRestoreGame);
return;
}
var currentScene = window.stats.scene;
var scene = new Scene("choicescript_stats", window.stats, this.nav, {secondaryMode:"stats", saveSlot:"temp"});
main.innerHTML = "
"]; } else if (hiddenCount == 1) { buffer = ["You haven't unlocked any achievements yet. There are "+spell(totalAchievements)+" possible achievements (including one hidden achievement), worth a total of "+totalScore+" points.
"]; } else if (hiddenCount == totalAchievements) { buffer = ["You haven't unlocked any achievements yet. There are "+spell(totalAchievements)+" hidden achievements, worth a total of "+totalScore+" points.
"]; } else { buffer = ["You haven't unlocked any achievements yet. There are "+spell(totalAchievements)+" possible achievements (including "+spell(hiddenCount)+" hidden achievements), worth a total of "+totalScore+" points.
"]; } if (lockedBuffer.length) { buffer.push.apply(buffer, lockedBuffer); buffer.push("
"); } } else if (score == totalScore) { if (totalAchievements == 2) { buffer = ["Congratulations! You have unlocked both achievements, earning a total of "+score+" points, a perfect score.
"]; } else { buffer = ["Congratulations! You have unlocked all "+spell(totalAchievements)+" achievements, earning a total of "+score+" points, a perfect score.
"]; } buffer.push.apply(buffer, unlockedBuffer); buffer.push("
"); } else { buffer = ["You have unlocked "+spell(achievedCount)+" out of "+spell(totalAchievements)+" possible achievements, earning you a score of "+score+" out of a possible "+totalScore+" points.
"]; buffer.push.apply(buffer, unlockedBuffer); var remaining = totalAchievements-achievedCount; if (remaining == hiddenCount) { if (remaining == 1) { buffer.push("
There is still one hidden achievement remaining.
"); } else { buffer.push("
There are still " + spell(remaining) + " hidden achievements remaining.
"); } } else if (hiddenCount > 1) { buffer.push("
There are still "+spell(remaining)+" achievements remaining, including "+spell(hiddenCount)+" hidden achievements.
"); } else if (hiddenCount == 1) { buffer.push("
There are still "+spell(remaining)+" achievements remaining, including one hidden achievement.
"); } else if (remaining == 1) { buffer.push("
There is still one achievement remaining.
"); } else { buffer.push("
There are still "+spell(remaining)+" achievements remaining.
"); } if (lockedBuffer.length) { buffer.push.apply(buffer, lockedBuffer); buffer.push("
"); } } target.innerHTML = buffer.join(""); } function callIos(scheme, path) { if (!window.isIosApp) return; if (path) { path = encodeURIComponent(path); } else { path = ""; } setTimeout(function() { var iframe = document.createElement("IFRAME"); iframe.setAttribute("src", scheme + "://" + path); document.documentElement.appendChild(iframe); iframe.parentNode.removeChild(iframe); iframe = null; }, 0); } function asyncAlert(message, callback) { if (!callback) callback = function(){}; if (window.isIosApp) { window.alertCallback = callback; callIos("alert", message); } else if (window.isAndroidApp) { setTimeout(function() { alert(message); if (callback) callback(); }, 0); } else if (window.isWinOldApp) { setTimeout(function() { window.external.Alert(message); if (callback) callback(); }, 0); } else { alertify.alert(message, function() {safeCall(null, callback);}); } } function asyncConfirm(message, callback) { if (false/*window.isIosApp*/) { // TODO asyncConfirm window.confirmCallback = callback; callIos("confirm", message); } else if (window.isAndroidApp) { setTimeout(function() { var result = confirm(message); if (callback) callback(result); }, 0); } else if (window.isWinOldApp) { setTimeout(function() { var result = window.external.Confirm(message); if (callback) callback(result); }, 0); } else { alertify.confirm(message, function(result) {safeCall(null, callback(result));}); } } function clearScreen(code) { // can't create div via innerHTML; div mysteriously doesn't show up on iOS main.innerHTML = ""; var text = document.createElement("div"); text.setAttribute("id", "text"); main.appendChild(text); var useAjax = true; if (isWeb && window.noAjax) { useAjax = false; } if (useAjax) { doneLoading(); setTimeout(function() { if (window.isChromeApp) { document.body.firstElementChild.scrollIntoView(); } else { window.scrollTo(0,0); } }, 0); safeCall(null, code); } else { if (!initStore()) alert("Your browser has disabled cookies; this game requires cookies to work properly. Please re-enable cookies and refresh this page to continue."); startLoading(); var form = window.document.createElement("form"); var axn = window.location.protocol + "//" + window.location.host + window.location.pathname; form.setAttribute("action", axn); form.setAttribute("method", "POST"); main.appendChild(form); form.submit(); } } function safeSubmit(code) { return function safelySubmitted() { safeCall(code); return false; }; } function startLoading() { var loading = document.getElementById('loading'); if (!loading) { safeCall(null, function() { loading = document.createElement('div'); loading.setAttribute("id", "loading"); loading.innerHTML = "
Loading...
"+ (/MSIE [67]/.test(navigator.userAgent)?"":"")+ "
"; main.appendChild(loading); }); } } function doneLoading() { var loading = document.getElementById('loading'); if (loading) loading.parentNode.removeChild(loading); // TODO update header? } function setClass(element, classString) { element.setAttribute("class", classString); element.setAttribute("className", classString); } function printFooter() { // var footer = document.getElementById('footer'); // We could put anything we want in the footer here, but perhaps we should avoid it. var statsButton = document.getElementById("statsButton"); if (statsButton) { if (window.stats.scene.secondaryMode == "stats") { statsButton.innerHTML = "Return to the Game"; } else { statsButton.innerHTML = "Show Stats"; if (window.isAndroidApp && window.statsMode.get()) { showStats(); } } } setTimeout(function() {callIos("curl");}, 0); } // retrieve value of HTML form function getFormValue(name) { var field = document.forms[0][name]; if (!field) return ""; // may return either one field or an array of fields if (field.checked) return field.value; for (var i = 0; i < field.length; i++) { var element = field[i]; if (element.checked) return element.value; } return null; } function printOptions(groups, options, callback) { var form = document.createElement("form"); main.appendChild(form); var self = this; form.action="#"; form.onsubmit = function() { safeCall(self, function() { var currentOptions = options; var option, group; for (var i = 0; i < groups.length; i++) { if (i > 0) { currentOptions = option.suboptions; } group = groups[i]; if (!group) group = "choice"; var value = getFormValue(group); if (value === null || value === undefined) { if (groups.length == 1) { asyncAlert("Please choose one of the available options first."); } else { var article = "a"; if (/^[aeiou].*/i.test(group)) article = "an"; asyncAlert("Please choose " + article + " " + group + " first."); } return; } option = currentOptions[value]; } if (groups.length > 1 && option.unselectable) { asyncAlert("Sorry, that combination of choices is not allowed. Please select a different " + groups[groups.length-1] + "."); return; } safeCall(null, function() {callback(option);}); }); return false; }; if (!options) throw new Error(this.lineMsg()+"undefined options"); if (!options.length) throw new Error(this.lineMsg()+"no options"); // global num will be used to assign accessKeys to the options var globalNum = 1; var currentOptions = options; var div = document.createElement("div"); form.appendChild(div); setClass(div, "choice"); for (var groupNum = 0; groupNum < groups.length; groupNum++) { var group = groups[groupNum]; if (group) { var textBuilder = ["Select "]; textBuilder.push(/^[aeiou]/i.test(group)?"an ":"a "); textBuilder.push(group); textBuilder.push(":"); var p = document.createElement("p"); p.appendChild(document.createTextNode(textBuilder.join(""))); div.appendChild(p); } var checked = null; for (var optionNum = 0; optionNum < currentOptions.length; optionNum++) { var option = currentOptions[optionNum]; if (!checked && !option.unselectable) checked = option; var isLast = (optionNum == currentOptions.length - 1); printOptionRadioButton(div, group, option, optionNum, globalNum++, isLast, checked == option); } // for rendering, the first options' suboptions should be as good as any other currentOptions = currentOptions[0].suboptions; } form.appendChild(document.createElement("br")); var useRealForm = false; if (useRealForm) { printButton("Next", form, false); } else { printButton("Next", main, false, function() { form.onsubmit(); }); } } function printOptionRadioButton(div, name, option, localChoiceNumber, globalChoiceNumber, isLast, checked) { var line = option.name; var unselectable = false; if (!name) unselectable = option.unselectable; var disabledString = unselectable ? " disabled" : ""; var id = name + localChoiceNumber; if (!name) name = "choice"; var radio; var div2 = document.createElement("div"); var label = document.createElement("label"); // IE doesn't allow you to dynamically specify the name of radio buttons if (!/^\w+$/.test(name)) throw new Error("invalid choice group name: " + name); label.innerHTML = ""; label.setAttribute("for", id); if (localChoiceNumber === 0) { if (isLast) { setClass(label, "onlyChild"+disabledString); } else { setClass(label, "firstChild"+disabledString); } } else if (isLast) { setClass(label, "lastChild"+disabledString); } else if (unselectable) { setClass(label, "disabled"); } label.setAttribute("accesskey", globalChoiceNumber); if (!unselectable) { if (window.Touch) { // Make labels clickable on iPhone label.onclick = function labelClick(evt) { try { var target = evt.target; if (!/label/i.test(target.tagName)) return; var button = document.getElementById(target.getAttribute("for")); button.checked = true; } catch (e) {} }; } else if (/MSIE 6/.test(navigator.userAgent)) { label.onclick = function labelClick() { try { var target = window.event.srcElement; if (!/label/i.test(target.tagName)) return; var button = document.getElementById(target.getAttribute("for")); button.checked = true; } catch (e) {} }; } } printx(line, label); div2.appendChild(label); div.appendChild(div2); } function printImage(source, alignment) { var img = document.createElement("img"); img.src = source; setClass(img, "align"+alignment); document.getElementById("text").appendChild(img); } function playSound(source) { for (var existingAudios = document.getElementsByTagName("audio"); existingAudios.length;) { existingAudios[0].parentNode.removeChild(existingAudios[0]); } var audio = document.createElement("audio"); if (audio.play) { audio.setAttribute("src", source); document.body.appendChild(audio); audio.play(); } } function moreGames() { if (window.isIosApp) { window.location.href = "itms-apps://itunes.com/apps/choiceofgames"; } else if (window.isAndroidApp) { if (window.isNookAndroidApp) { asyncAlert("Please search the Nook App Store for \"Choice of Games\" for more games like this!"); return; } if (window.isAmazonAndroidApp) { var androidLink = document.getElementById('androidLink'); if (androidLink && androidLink.href) { androidUrl = androidLink.href; var package = /id=([\.\w]+)/.exec(androidUrl)[1]; window.location.href = "http://www.amazon.com/gp/mas/dl/android?p="+package+"&showAll=1&t=choofgam-20&ref=moreGames"; } else { window.location.href = "http://www.amazon.com/gp/mas/dl/android?p=com.choiceofgames.dragon&showAll=1&t=choofgam-20&ref=moreGames"; } } else { window.location.href = "market://search?q=pub:%22Choice+of+Games+LLC"; } } else { try { if (window.isChromeApp) { window.open("https://www.choiceofgames.com/category/our-games/"); } else { window.location.href = "https://www.choiceofgames.com/category/our-games/"; } } catch (e) { // in xulrunner, this will be blocked, but it will trigger opening the external browser } } } function printShareLinks(target, now) { if (!target) target = document.getElementById('text'); var msgDiv = document.createElement("div"); if (window.isIosApp) { if (now) { callIos("share"); return; } var button = document.createElement("button"); button.appendChild(document.createTextNode("Share This Game")); button.onclick = function() { callIos("share"); }; msgDiv.appendChild(button); msgDiv.appendChild(document.createElement("br")); // insert our own paragraph break, to matchPlease support our work by sharing this game with friends! The more people play, the more resources we'll have to work on the next game.
"; msgDiv.innerHTML = nowMsg + "Please sign in to Choiceofgames.com to restore purchases.
"; loginForm(document.getElementById('text'), /*optional*/1, /*err*/null, callback); }); } }); } else { safeTimeout(callback, 0); } } // Callback expects a localized string, or "", or "free", or "guess" function getPrice(product, callback) { if (window.isIosApp) { window.priceCallback = callback; callIos("price", product); } else if (window.isAndroidApp) { // TODO: support android price localization? safeTimeout(function () { callback.call(this, "guess"); }, 0); } else { safeTimeout(function () { callback.call(this, "guess"); }, 0); } } // Callback expects no args, but should only be called on success function purchase(product, callback) { var purchaseCallback = function() { window.purchaseCallback = null; safeCall(null, callback); }; if (window.isIosApp) { window.purchaseCallback = purchaseCallback; callIos("purchase", product); } else if (window.isAndroidApp) { window.purchaseCallback = purchaseCallback; androidBilling.purchase(product); } else if (window.isWinOldApp) { window.external.Purchase(product); } else if (window.isMacApp && window.macPurchase) { macPurchase.purchase_(product); } else if (window.isCef) { cefQuerySimple("Purchase " + product); // no callback; we'll refresh on purchase } else if (isWebPurchaseSupported()) { if (!window.StripeCheckout) return asyncAlert("Sorry, we weren't able to initiate payment. (Your "+ "network connection may be down.) Please refresh the page and try again, or contact "+ "support@choiceofgames.com for assistance."); startLoading(); isRegistered(function(registered) { doneLoading(); var fullProductName = window.storeName + "." + product; function stripe(email) { startLoading(); xhrAuthRequest("GET", "product-data", function(ok, data) { doneLoading(); if (!ok) return asyncAlert("Sorry, we weren't able to initiate payment. (Your "+ "network connection may be down.) Please refresh the page and try again, or contact "+ "support@choiceofgames.com for assistance."); data = data[fullProductName]; StripeCheckout.open({ key: window.stripeKey, address: false, amount: data.amount, name: data.display_name, email: email, panelLabel: 'Buy', token: function(response) { clearScreen(function() { startLoading(); xhrAuthRequest("POST", "purchase", function(ok, response) { doneLoading(); if (ok) { cacheKnownPurchases(response); return callback(); } else if (/^card error: /.test(response.error)) { var cardError = response.error.substring("card error: ".length); asyncAlert(cardError); clearScreen(loadAndRestoreGame); } else if ("purchase already in flight" == response.error) { asyncAlert("Sorry, there was an error handling your purchase. Please wait five minutes and try again, or contact support@choiceofgames.com for assistance."); clearScreen(loadAndRestoreGame); } else { asyncAlert("Sorry, there was an error processing your card. (Your "+ "network connection may be down.) Please refresh the page and try again, or contact "+ "support@choiceofgames.com for assistance."); clearScreen(loadAndRestoreGame); } }, "stripeToken", response.id, "product", fullProductName, "key", window.stripeKey); }); } }); }, "products", fullProductName); } if (registered) return fetchEmail(stripe); clearScreen(function() { var target = document.getElementById('text'); target.innerHTML="Please sign in to Choiceofgames.com to purchase.
"; loginForm(document.getElementById('text'), /*optional*/1, /*err*/null, function(registered){ if (registered) { checkPurchase(product, function(ok, response) { if (ok && response[product]) { callback(); } else { clearScreen(loadAndRestoreGame); return fetchEmail(stripe); } }); } else { clearScreen(loadAndRestoreGame); } }); }); }); } else { safeTimeout(callback, 0); } } function registerNativeAchievement(name) { if (window.blockNativeAchievements) return; if (window.isIosApp) { callIos("achieve", name+"/"); } else if (window.isMacApp && window.macAchievements) { macAchievements.achieve_(name); } else if (window.isWinOldApp) { window.external.Achieve(name); } else if (window.isCef) { cefQuerySimple("Achieve " + name); } } function achieve(name, title, description) { if (initStore()) window.store.set("achieved", toJson(nav.achieved)); registerNativeAchievement(name); // iOS shows a prominent banner; no need to show our own if (window.isIosApp) return; var escapedTitle = title+"".replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"'); var escapedDescription = description+"".replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/\[b\]/g, '') .replace(/\[\/b\]/g, '') .replace(/\[i\]/g, '') .replace(/\[\/i\]/g, ''); var html = "Achievement: "+escapedTitle+"Do you have a Choiceofgames.com password?
"+ "