From c0818636dda70e4ff30c1e85b902fa0992b4c33a Mon Sep 17 00:00:00 2001
From: Alex Xu <alex_y_xu@yahoo.ca>
Date: Sun, 30 Jun 2013 19:55:42 -0400
Subject: workering

---
 www/css/anim.css  |  16 +++
 www/css/index.css |  14 ++-
 www/index.html    |  21 ++--
 www/js/api.js     | 104 ++++++++++++++---
 www/js/html5ks.js | 335 +++++++++++++++++++++++++++++-------------------------
 www/js/menu.js    |  33 +++++-
 6 files changed, 335 insertions(+), 188 deletions(-)

(limited to 'www')

diff --git a/www/css/anim.css b/www/css/anim.css
index ee2889d..e89959d 100644
--- a/www/css/anim.css
+++ b/www/css/anim.css
@@ -22,3 +22,19 @@
   0% { opacity: 1; }
   100% { opacity: 0; }
 }
+
+@-webkit-keyframes blink {
+  0% { opacity: 0; }
+  50% { opacity: 1; }
+  100% { opacity: 0; }
+}
+@-moz-keyframes blink {
+  0% { opacity: 0; }
+  50% { opacity: 1; }
+  100% { opacity: 0; }
+}
+@keyframes blink {
+  0% { opacity: 0; }
+  50% { opacity: 1; }
+  100% { opacity: 0; }
+}
diff --git a/www/css/index.css b/www/css/index.css
index 533559c..e5a5c19 100644
--- a/www/css/index.css
+++ b/www/css/index.css
@@ -27,6 +27,8 @@ body {
 #container, #bg, #vid {
   cursor: url("../dump/ui/mousecursor.png"), default;
   position: absolute;
+}
+#container.scale, #bg.scale, #vid.scale {
   top: 50%;
   left: 50%;
 }
@@ -96,7 +98,6 @@ html.no-js #warn-container {
 h2 {
   font: 20px/28px Playtime;
   font-weight: bold;
-  opacity: 0.4;
 }
 html.no-js #warn li:not(#js) { display: none; }
            #warn li#ie { display: none; }
@@ -109,8 +110,7 @@ html #warn li#html-svg-filter { display: none; }
 label {
   display: block;
 }
-.button-enabled {
-/* cursor: pointer; */
+.button, h2, label {
   opacity: 0.4;
 }
 .button-disabled {
@@ -141,3 +141,11 @@ input[type="checkbox"] + span:before {
 input[type="checkbox"]:checked + span:before {
   background: url("../dump/ui/bt-cf-checked.png") no-repeat left bottom;
 }
+#ctc {
+  position: absolute;
+  bottom: 20px;
+  right: 10px;
+  -webkit-animation: blink 2s infinite;
+  -moz-animation: blink 2s infinite;
+  animation: blink 2s infinite;
+}
diff --git a/www/index.html b/www/index.html
index 19b109c..b01fea4 100644
--- a/www/index.html
+++ b/www/index.html
@@ -49,6 +49,7 @@
         <img id="window-image" src="dump/ui/bg-say.png" alt="">
         <div id="who"></div>
         <div id="say"></div>
+        <img id="ctc" src="dump/ui/ctc.png" style="display: none">
       </div>
       <div id="main-menu" style="display: none;">
         <div id="main-menu-buttons" style="top: 377px; position: absolute; left: 81px;">
@@ -67,18 +68,18 @@
       <div id="dialogs" style="display: none; position: absolute; top: 50%; width: 504px; height: 395px; background: url(dump/ui/bg-config.png); left: 50%; margin-left: -252px; margin-top: -197.5px;">
         <div id="options" style="padding: 10px 20px;">
           <h2>Options</h2>
-          <label class="button button-enabled"><input type="checkbox" id="hdisable"> <span>Disable adult content</span></label>
-          <label class="button button-enabled"><input type="checkbox" id="fullscreen"> <span>Fullscreen mode</span></label>
-          <label class="button button-enabled"><input type="checkbox" id="skip-unread"> <span>Skip unread text</span></label>
-          <label class="button button-enabled"><input type="checkbox" id="skip-after-choices"> <span>Keep skipping after choices</span></label>
-          <label class="button button-enabled"><input type="checkbox" id="use-webp"> <span>Use WebP images (less bandwidth, more CPU)</span></label>
-          <label class="button button-enabled"><input type="checkbox" id="scale-video"> <span>Scale video to fullscreen (decreases performance)</span></label>
+          <label class="button button-enabled"><input type="checkbox" class="option" id="hdisable"> <span>Disable adult content</span></label>
+          <label class="button button-enabled"><input type="checkbox" class="option" id="skipUnread"> <span>Skip unread text</span></label>
+          <label class="button button-enabled"><input type="checkbox" class="option" id="skipAfterChoices"> <span>Keep skipping after choices</span></label>
+          <label class="button button-enabled"><input type="checkbox" class="option" id="useWebP"> <span>Use WebP images (less bandwidth, more CPU)</span></label>
+          <label class="button button-enabled"><input type="checkbox" class="option" id="fullscreen"> <span>Scale content</span></label>
+          <label class="button button-enabled"><input type="checkbox" class="option" id="scaleVideo"> <span>Scale video</span></label>
 
-          <label><input type="range" id="text-speed"> <span class="tr">Text speed</span></label>
-          <label><input type="range" id="auto-mode-delay"> <span class="tr">Auto mode delay</span></label>
+          <label><input type="range" min="0.0" max="1.0" step="0.001" class="option" id="textSpeed"> <span class="tr">Text speed</span></label>
+          <label><input type="range" min="0.0" max="1.0" step="0.001" class="option" id="autoModeDelay"> <span class="tr">Auto mode delay</span></label>
 
-          <label><input type="range" id="music-volume"> <span class="tr">Music volume</span></label>
-          <label><input type="range" id="sfx-volume"> <span class="tr">SFX volume</span> <span id="test-sfx" class="button button-enabled"><img src="dump/ui/bt-musicplay.png"> Test</span></label>
+          <label><input type="range" min="0.0" max="1.0" step="0.001" class="option" id="musicVolume"> <span class="tr">Music volume</span></label>
+          <label><input type="range" min="0.0" max="1.0" step="0.001" class="option" id="sfxVolume"> <span class="tr">SFX volume</span> <span id="test-sfx" class="button button-enabled"><img src="dump/ui/bt-musicplay.png"> Test</span></label>
         </div>
         <div id="return" class="button button-enabled" style="position: absolute; bottom: 15px; right: 20px;">
           <img src="dump/ui/bt-return.png">
diff --git a/www/js/api.js b/www/js/api.js
index 128cd9c..1aec74d 100644
--- a/www/js/api.js
+++ b/www/js/api.js
@@ -1,5 +1,14 @@
 "use strict";
 window.html5ks.api = {
+  init: function () {
+    var chars = html5ks.data.characters;
+    for (var ch in chars) {
+      var char = chars[ch];
+      if (char.name) {
+        char.name = this.tag(char.name);
+      }
+    }
+  },
   seen_scene: function (scene) {
     return !!html5ks.persistent.seen_scenes[scene];
   },
@@ -43,6 +52,11 @@ window.html5ks.api = {
     return deferred.promise;
   },
   stop: function (channel, fade) {
+    if (channel === "all") {
+      this.stop("music");
+      this.stop("sound");
+      return this.stop("ambient");
+    }
     var deferred = when.defer(),
         audio = html5ks.elements.audio[channel],
         fadeSet = html5ks.persistent.settings.fade;
@@ -68,6 +82,8 @@ window.html5ks.api = {
       video.src = src + "mp4";
     }
 
+    this.stop("all");
+
     video.load();
     video.style.display = "block";
     video.play();
@@ -115,13 +131,13 @@ window.html5ks.api = {
     var cmd = inst[0],
         args = inst.slice(1);
     if (html5ks.data.characters[cmd]) {
-      return this.character(cmd, args);
+      return this.character(cmd, args[0]);
     } else {
       if (this[cmd]) {
         return this[cmd].apply(this, args);
       } else if (/^[A-Z]/.test(cmd)) {
         console.log("cmd starts with caps, probably character");
-        return this.character(cmd, args);
+        return this.character(cmd, args[0]);
       } else {
         console.error("no such cmd " + cmd);
         var deferred = when.defer();
@@ -194,38 +210,92 @@ window.html5ks.api = {
     return deferred.promise;
   },
 
-  character: function (name, str) {
+  tag: function (str) {
+    var tags = [
+      /&/g, "&amp;",
+      /</g, "&lt;",
+      />/g, "&gt;",
+      /{b}/g, "<b>",
+      /{\/b}/g, "</b>",
+      /{s}/g, "<s>",
+      /{\/s}/g, "</s>",
+      /{size=(\d*)}/g, "<span style='color: $1'>",
+      /{\/size}/g, "</span>",
+      /{color=(\d*)}/g, "<span style='color: $1'>",
+      /{\/color}/g, "</span>",
+      /{w(=\d*\.\d*)?}.*/, "",
+      /{nw}/, "",
+      /{fast}/, ""
+    ];
+    for (var i = 0; i < tags.length - 1; i += 2) {
+      str = str.replace(tags[i], tags[i+1]);
+    }
+    return str;
+  },
+
+  character: function (name, str, extend) {
     var deferred = when.defer(),
-        text = str,
-        char = html5ks.data.characters[name];
+        text = this.tag(str),
+        char = html5ks.data.characters[name],
+        w = /{w(=\d*\.\d*)?}/.exec(str);
+
     if (!char) {
       char = { name: name };
     }
-    if (char.what_prefix) {
+    if (!extend && char.what_prefix) {
       text = char.what_prefix + text;
     }
-    if (char.what_suffix) {
+    if ((!w || !w[1] || extend) && char.what_suffix) {
       text = text + char.what_suffix;
     }
     var who = html5ks.elements.who;
-    who.textContent = char.name;
-    if (char.color) {
-      who.style.color = char.color;
+    if (!extend) {
+      who.innerHTML = char.name;
+      if (char.color) {
+        who.style.color = char.color;
+      } else {
+        who.style.color = "#ffffff";
+      }
+    }
+
+    if (extend) {
+      html5ks.elements.say.innerHTML += text;
     } else {
-      who.style.color = "#ffffff";
+      html5ks.elements.say.innerHTML = text;
     }
-    html5ks.elements.say.textContent = text;
-    html5ks.next = function () {
-      deferred.resolve(text);
-      html5ks.next = function () {};
-    };
-    if (html5ks.state.skip) {
+
+    if (w) {
+      html5ks.next = function () {
+        html5ks.next = function () {};
+        html5ks.api.extend(str.substring(w.index + w[0].length)).then(function () {
+          deferred.resolve();
+        });
+      };
+      if (w[1]) {
+        setTimeout(html5ks.next, parseFloat(w[1].substring(1), 10) * 1000);
+        return deferred.promise;
+      }
+    } else {
+      html5ks.next = function () {
+        html5ks.elements.ctc.style.display = "none";
+        deferred.resolve(text);
+        html5ks.next = function () {};
+      };
+    }
+    if (html5ks.state.skip || str.indexOf("{nw}") > -1) {
       html5ks.next();
     } else if (html5ks.state.auto) {
       setTimeout(html5ks.next, 1000 + html5ks.persistent.settings.autospeed * text.length);
+    } else {
+      html5ks.elements.ctc.style.display = "block";
     }
     return deferred.promise;
   },
+
+  extend: function (str) {
+    return this.character(null, str, true);
+  },
+
   Pause: function (duration) {
     var deferred = when.defer();
     setTimeout(function () {
diff --git a/www/js/html5ks.js b/www/js/html5ks.js
index a6518c0..653b407 100644
--- a/www/js/html5ks.js
+++ b/www/js/html5ks.js
@@ -1,174 +1,199 @@
-(function () {
-  "use strict";
-  window.html5ks = {
-    data: {
-      script: {}
+"use strict";
+window.html5ks = {
+  data: {
+    script: {}
+  },
+  persistent: {
+    seen_scenes: {},
+    attraction: {
+      kenji: 0,
+      sc: 0,
+      hanako: 0
     },
-    persistent: {
-      seen_scenes: {},
-      attraction: {
-        kenji: 0,
-        sc: 0,
-        hanako: 0
+    settings: {
+      fade: 100,
+      gotit: false,
+      hdisable: false,
+      skipUnread: false,
+      skipAfterChoices: false,
+      useWebP: null,
+      fullscreen: true,
+      scaleVideo: true,
+      textSpeed: 0.5,
+      autoModeDelay: 0.2,
+      musicVolume: 1,
+      sfxVolume: 1
+    },
+    store: {}
+  },
+  state: {},
+  initElements: function () {
+    this.elements = {
+      container: document.getElementById("container"),
+      video: document.getElementById("vid"),
+      audio: {
+        music: new Audio(),
+        ambient: new Audio(),
+        sound: new Audio()
       },
-      hdisabled: false,
-      settings: {
-        // ms per character
-        autospeed: 20,
-        fade: 100,
-        gotit: false,
-        scale: true
+      who: document.getElementById("who"),
+      say: document.getElementById("say"),
+      bg: document.getElementById("bg"),
+      window: document.getElementById("window"),
+      ctc: document.getElementById("ctc")
+    };
+    this.elements.audio.music.loop = true;
+    this.elements.audio.ambient.loop = true;
+  },
+  load: function () {
+    if (localStorage.persistent) {
+      this.persistent = JSON.parse(localStorage.persistent);
+      this.loaded = true;
+    }
+  },
+  save: function () {
+    localStorage.persistent = JSON.stringify(this.persistent);
+  },
+  scale: function () {
+    if (html5ks.persistent.settings.fullscreen) {
+      var newScale = 1;
+      var height = document.documentElement.clientHeight,
+          width = document.documentElement.clientWidth;
+      if (height / width <= 0.75) { // widescreen
+        newScale = height / 600;
+      } else {
+        newScale = width / 800;
       }
-    },
-    state: {
-      auto: false
-    },
-    initElements: function () {
-      this.elements = {
-        container: document.getElementById("container"),
-        video: document.getElementById("vid"),
-        audio: {
-          music: new Audio(),
-          ambient: new Audio(),
-          sound: new Audio()
-        },
-        who: document.getElementById("who"),
-        say: document.getElementById("say"),
-        bg: document.getElementById("bg"),
-        window: document.getElementById("window")
-      };
-      this.elements.audio.music.loop = true;
-      this.elements.audio.ambient.loop = true;
-    },
-    load: function () {
-      if (localStorage.persistent) this.persistent = JSON.parse(localStorage.persistent);
-    },
-    save: function () {
-      localStorage.persistent = JSON.stringify(this.persistent);
-    },
-    scale: function () {
-      if (html5ks.persistent.settings.scale) {
-        var newScale = 1;
-        var height = document.documentElement.clientHeight,
-            width = document.documentElement.clientWidth;
-        if (height / width <= 0.75) { // widescreen
-          newScale = height / 600;
-        } else {
-          newScale = width / 800;
-        }
 
-        var container = html5ks.elements.container;
-        container.style.webkitTransform = "scale(" + newScale + ")";
-        container.style.mozTransform = "scale(" + newScale + ")";
-        container.style.transform = "scale(" + newScale + ")";
+      var container = html5ks.elements.container;
+      container.style.webkitTransform = "scale(" + newScale + ")";
+      container.style.mozTransform = "scale(" + newScale + ")";
+      container.style.transform = "scale(" + newScale + ")";
+      container.className += " scale";
 
-        var applyScale = function (el, scale) {
-          el.style.height = scale * 600 + "px";
-          el.style.marginTop = "-" + scale * 300 + "px";
-          el.style.width = scale * 800 + "px";
-          el.style.marginLeft = "-" + scale * 400 + "px";
-        };
+      var applyScale = function (el, scale) {
+        el.style.height = scale * 600 + "px";
+        el.style.marginTop = "-" + scale * 300 + "px";
+        el.style.width = scale * 800 + "px";
+        el.style.marginLeft = "-" + scale * 400 + "px";
+        el.className += " scale";
+      };
 
-        applyScale(html5ks.elements.bg, newScale);
+      applyScale(html5ks.elements.bg, newScale);
+      if (html5ks.persistent.settings.scaleVideo) {
         applyScale(html5ks.elements.video, newScale);
       }
-    },
-    next: function () {},
-    initEvents: function () {
-      window.addEventListener("resize", html5ks.scale, false);
-      this.elements.container.addEventListener("mouseup", function () {
-        html5ks.next();
+    }
+  },
+  next: function () {},
+  initEvents: function () {
+    window.addEventListener("resize", html5ks.scale, false);
+    this.elements.container.addEventListener("mouseup", function () {
+      html5ks.next();
+    }, false);
+    var deselect = function () {
+      window.getSelection().collapse(this, 0);
+    };
+    document.body.addEventListener("mousemove", deselect, true);
+    document.body.addEventListener("mouseup", deselect, true);
+    document.body.addEventListener("keyup", deselect, true);
+  },
+  warnUnsupported: function () {
+    if (!html5ks.persistent.settings.gotit) {
+      var warn = document.getElementById("warn-container");
+      document.getElementById("gotit").addEventListener("mouseup", function () {
+        warn.style.mozAnimation = "0.5s dissolveout";
+        warn.style.webkitAnimation = "0.5s dissolveout";
+        warn.style.animation = "0.5s dissolveout";
+        warn.style.opacity = 0;
+        html5ks.persistent.settings.gotit = true;
+        html5ks.start();
       }, false);
-      var deselect = function () {
-        window.getSelection().collapse(this, 0);
-      };
-      document.body.addEventListener("mousemove", deselect, true);
-      document.body.addEventListener("mouseup", deselect, true);
-      document.body.addEventListener("keyup", deselect, true);
-    },
-    warnUnsupported: function () {
-      if (!html5ks.persistent.settings.gotit) {
-        var warn = document.getElementById("warn-container");
-        document.getElementById("gotit").addEventListener("mouseup", function () {
-          warn.style.mozAnimation = "0.5s dissolveout";
-          warn.style.webkitAnimation = "0.5s dissolveout";
-          warn.style.animation = "0.5s dissolveout";
-          warn.style.opacity = 0;
-          html5ks.persistent.settings.gotit = true;
-          html5ks.start();
-        }, false);
-        var warns = document.getElementById("warns").children;
-        if (/MSIE/.test(navigator.userAgent)) {
-          document.getElementById("ie").style.display = "block";
-        }
-        if (!(/Firefox/.test(navigator.userAgent))) {
-          document.getElementById("html-svg-filter").style.display = "block";
-        }
-        for (var i = 0; i < warns.length; i++) {
-          if (window.getComputedStyle(warns[i]).getPropertyValue("display") !== "none") {
-            warn.style.visibility = "visible";
-            return true;
-          }
-        }
+      var warns = document.getElementById("warns").children;
+      if (/MSIE/.test(navigator.userAgent)) {
+        document.getElementById("ie").style.display = "block";
       }
-    },
-    onload: function () {
-      this.initElements();
-      this.load();
-      this.scale();
-      this.initEvents();
-      if (!this.warnUnsupported()) {
-        this.start();
+      if (!(/Firefox/.test(navigator.userAgent))) {
+        document.getElementById("html-svg-filter").style.display = "block";
       }
-      this.menu.init();
-    },
-    start: function () {
-      this.fetch("script", "a1-monday").then(function () {
-        html5ks.api.movie_cutscene("4ls").then(function () {
-          html5ks.menu.mainMenu();
-        });
+      for (var i = 0; i < warns.length; i++) {
+        if (window.getComputedStyle(warns[i]).getPropertyValue("display") !== "none") {
+          warn.style.visibility = "visible";
+          return true;
+        }
+      }
+    }
+  },
+  onload: function () {
+    this.initElements();
+    this.load();
+    this.scale();
+    this.initEvents();
+    if (!this.warnUnsupported()) {
+      this.start();
+    }
+    this.api.init();
+    this.menu.init();
+  },
+  winload: function () {
+    if (!this.loaded) {
+      this.persistent.settings.useWebP = Modernizr.webp;
+    }
+    if (!Modernizr.webp && this.persistent.settings.useWebP) {
+      var webpjs = document.createElement("script");
+      webpjs.src = "js/webpjs-0.0.2.min.js";
+      document.head.appendChild(webpjs);
+    }
+  },
+  start: function () {
+    this.fetch("script", "a1-monday").then(function () {
+      html5ks.api.movie_cutscene("4ls").then(function () {
+        html5ks.menu.mainMenu();
       });
-    },
-    fetch: function (type, name) {
-      var deferred = when.defer();
-      var xhr = new XMLHttpRequest();
-      switch (type) {
-        case "script":
-          var script = html5ks.data.script;
-          if (script[name]) {
-            deferred.resolve();
-          } else {
-            xhr.open("GET", "scripts/script-" + name + ".json");
-            xhr.onreadystatechange = function () {
-              script[name] = true;
-              if (xhr.readyState === 4) {
-                var resp = JSON.parse(xhr.responseText);
-                for (var label in resp) {
-                  script[label] = resp[label];
-                }
-                deferred.resolve();
-              }
-            };
-            xhr.send();
-          }
-          break;
-        case "imachine":
-          xhr.open("GET", "scripts/imachine.json");
+    });
+  },
+  fetch: function (type, name) {
+    var deferred = when.defer();
+    var xhr = new XMLHttpRequest();
+    switch (type) {
+      case "script":
+        var script = html5ks.data.script;
+        if (script[name]) {
+          deferred.resolve();
+        } else {
+          xhr.open("GET", "scripts/script-" + name + ".json");
           xhr.onreadystatechange = function () {
+            script[name] = true;
             if (xhr.readyState === 4) {
-              html5ks.data.imachine = JSON.parse(xhr.responseText);
+              var resp = JSON.parse(xhr.responseText);
+              for (var label in resp) {
+                script[label] = resp[label];
+              }
               deferred.resolve();
             }
           };
           xhr.send();
-          break;
-        default:
-          throw new Error("fetchtype " + type + " not implemented");
-      }
-      return deferred.promise;
+        }
+        break;
+      case "imachine":
+        xhr.open("GET", "scripts/imachine.json");
+        xhr.onreadystatechange = function () {
+          if (xhr.readyState === 4) {
+            html5ks.data.imachine = JSON.parse(xhr.responseText);
+            deferred.resolve();
+          }
+        };
+        xhr.send();
+        break;
+      default:
+        throw new Error("fetchtype " + type + " not implemented");
     }
-  };
-  document.addEventListener("DOMContentLoaded", function () {
-    html5ks.onload();
-  }, false);
-}());
+    return deferred.promise;
+  }
+};
+document.addEventListener("DOMContentLoaded", function () {
+  html5ks.onload();
+}, false);
+window.addEventListener("onload", function () {
+  html5ks.winload();
+}, false);
diff --git a/www/js/menu.js b/www/js/menu.js
index 589ae41..a57f9a0 100644
--- a/www/js/menu.js
+++ b/www/js/menu.js
@@ -14,15 +14,16 @@
     activeDialog: null,
 
     dialog: function (name) {
-      this.activeDialog = html5ks.elements.dialog[name];
+      this.activeDialog = this.elements.dialog[name];
       this.activeDialog.style.display = "block";
-      html5ks.elements.dialogs.style.display = "block";
+      this.elements.dialogs.style.display = "block";
     },
 
     initElements: function () {
       this.elements = {
         dialogs: document.getElementById("dialogs"),
         dialog: {
+          options: document.getElementById("options"),
           return: document.getElementById("return")
         },
         mainMenu: document.getElementById("main-menu"),
@@ -33,8 +34,34 @@
       };
     },
 
+    initOptions: function () {
+      var options = document.getElementsByClassName("option"),
+          values = html5ks.persistent.settings;
+
+      for (var i = options.length - 1; i >= 0; i--) {
+        var option = options[i];
+        switch (option.type) {
+          case "checkbox":
+            option.checked = values[option.id];
+            option.addEventListener("change", function () {
+                    values[this.id] = this.checked;
+            }, false);
+            break;
+          case "range":
+            option.value = values[option.id];
+            option.addEventListener("change", function () {
+                    values[this.id] = this.value;
+            }, false);
+            break;
+          default:
+            console.error("unknown option type %s", option.type);
+        }
+      }
+    },
+
     init: function () {
       this.initElements();
+      this.initOptions();
       this.elements.main.start.addEventListener("click", function () {
         if (this._imachine_loaded) {
           this.elements.mainMenu.style.display = "none";
@@ -46,7 +73,7 @@
       }, false);
       this.elements.dialog.return.addEventListener("click", function (e) {
         html5ks.menu.activeDialog.style.display = "none";
-        html5ks.elements.dialogs.style.display = "none";
+        html5ks.menu.elements.dialogs.style.display = "none";
       }, false);
       html5ks.fetch("imachine").then(function () {
         var start = this.elements.main.start;
-- 
cgit v1.2.3-70-g09d2