<commit_before>// Relate animation drawing to window frame rate
window.requestAnimFrame = (function () {
    return window.requestAnimationFrame  ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
          function (callback) {
            window.setTimeout(callback, 1000 / 60);
        };
}());

/** NOT for animations/movement! This is strictly for single key press logic. */
window.addEventListener('keydown', function (e) {
    if (g.currentPuzzle === undefined) {
        //console.log("no puzzle");
        g.handleKeyDownEvent(e.keyCode);
    } else {
        //console.log("yes puzzle");
        // TODO: do puzzles want to hear key events??
        //g.currentPuzzle.handleKeyDownEvent(e.keyCode);
    }
});

window.addEventListener('keyup', function (e) {
    if (g.currentPuzzle === undefined) {
        g.handleKeyUpEvent(e.keyCode);
    } else {
        // TODO: do puzzles want to hear key events??
        //g.currentPuzzle.handleKeyUpEvent(e.keyCode);
    }
});

/** Array containing all currently pressed keys. This is for animations/movement. */
var keys = window.uwetech.Input.keys; // code is in input.js

var BOX_WIDTH = 29; // width of the player bounding box for collisions
var BOX_HEIGHT = 24; // height of the player bounding box for collisions

//  constants!     W 87, S 83, A 65, D 68, space 32
var W_KEY = 87;
var S_KEY = 83;
var A_KEY = 65;
var D_KEY = 68;
var P_KEY = 80;
var LEFT_KEY  = 37;
var UP_KEY    = 38;
var RIGHT_KEY = 39;
var DOWN_KEY  = 40;
var ENTER_KEY = 13;
var SPACE_KEY = 32;
var DEBUG_KEY = 192;  // ` key ~ key  is the debug key

/** Bottom canvas is for the background. NO ANIMATIONS. */
var btmcanvas = document.getElementById('bottomlayer'),
    btmctx = btmcanvas.getContext('2d');

/** Middle canvas is for drawing sprites & other animated stuff. */
var midcanvas = document.getElementById('middlelayer'),
    midctx = midcanvas.getContext('2d');

/** Top canvas will draw on top of bottom and middle canvas. */
var topcanvas = document.getElementById('toplayer'),
    topctx = topcanvas.getContext('2d');

/** Loading screen canvas, or something. */
var loadcanvas = document.getElementById('loadlayer'),
    loadctx = loadcanvas.getContext('2d');

/** Loading screen canvas, or something. */
var timercanvas = document.getElementById('timerlayer'),
    timerctx = timercanvas.getContext('2d');

/** BTW: Other canvases exist you don't know about are in the HTML file. */

/** Represents the 2D array for the zone's boundaries.
 *  0 == walkable space
 *  1 == non walkable space
 *  2 == exit exists here
 *  ___ == ????
 */
var sign_screen_bounds = null;

// Keeps the player in bounds -- Kirsten update: no longer being used.
var math = function() {
  this.clamp = function(i, min, max) {
    return Math.max(Math.min(i, max),min);
  };
};
// TODO: What is this for?
function distance(a, b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return Math.sqrt(dx * dx + dy * dy);
}

//http://stackoverflow.com/questions/306316/determine-if-two-rectangles-overlap-each-other
function is_collide(a, b) {

  var ax_1 = a.x - 15;
  var ax_2 = a.x + BOX_WIDTH + 45; // + 32 is player width but 31 is smoother
  var ay_1 = a.y + 10;
  var ay_2 = a.y + BOX_HEIGHT + 70; // + 32 is height of player's box (ignores head collisions)

  var bx_1 = b.x;
  var bx_2 = b.x + BOX_WIDTH; // + 32 is player width but 31 is smoother
  var by_1 = b.y;
  var by_2 = b.y + BOX_HEIGHT;

  return (ax_1 < bx_2 && ax_2 > bx_1 && ay_1 < by_2 && ay_2 > by_1);
}

/**
 *  The camera will control what part of a map we're viewing and where
 *  the entities will be drawn on screen relative to current camera view
 * @constructor
 */
var Camera = function () {
    /**
     * Recalculate camera position based entirely on the passed
     * entity's x and y location. (entity should be player!!)
     *
     * Requires background.image.width/height and midcanvas.width/height
     * to determine edges of map and center the player correctly.
     * @param entity Should be player.
     */
    this.setup = function(entity) {
          //this.x = (canvas.width / 2) - entity.x;
          //this.y = (canvas.height / 2) - entity.y;

          // these variables determine where the camera starts
          this.x = (midcanvas.width / 2) - entity.x;
          this.y = (midcanvas.height / 2) - entity.y;

          // these if elseif blocks prevent the camera from moving
          // off the edge of the map

          // if the right side of the camera would go off the side...
          if (entity.x + (midcanvas.width / 2) > background.image.width) {
            // set it to the rightmost legal position
            this.x = midcanvas.width - background.image.width;
          } // if the left side would go off...
          else if(entity.x - (midcanvas.width / 2) < 0) {
            // set it to the leftmost legal position
            this.x = 0;
          }
          // if the top of the camera would scroll off
          if (entity.y - (midcanvas.height / 2) < 0 ) {
              // set it to the bottommost legal position
              this.y = 0;
            } // if the bottom of the camera would scroll off
            else if((midcanvas.height / 2) + entity.y > background.image.height) {
              // set it to the topmost legal position
              this.y = midcanvas.height - background.image.height;
            }
    };

    /**
     * Currently redirects to setup(), as the calculation is the same.
     * @param entity Should be the player.
     */
      this.getPosition = function (entity) {
          this.setup(entity);
      };
      //    function(entity) {
      //  this.x = (canvas.width / 2) - entity.x;
      //  this.y = (canvas.height / 2) - entity.y;
      //};
};

/**
 * Creates a new sprite. What is a sprite? A sprite is an object that has a visual
 * representation (spritesheet image), has a location in the world (x, y). Some
 * sprites may have additional functionality (ex: player sprites have speed).
 * @constructor
 */
var Sprite = function() {
    this.load = false;
    this.imgX = 0; // TODO: What is imgX for?

    /**
     * Lots of parameter options! Yay! Seriously though, most of these parameters are
     * needed to draw the image for this sprite correctly.
     */
    this.setOptions = function(src, srcX, srcY, dtx, dty, x, y, width, height, speed) {
            this.srcX = srcX;
            this.srcY = srcY;
            this.dtx = dtx;
            this.dty = dty;
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            this.speed = speed;
           // this.facing = "south";
            this.dialog = [];
            this.talkTo = false;
            this.faceSpot = 0;// Used to check if you want the dialog on left or right
                                // O is left 1 is right
            this.faceArray = []; // Used to check which face you want to show
            this.face = new Image();
            this.visualRadius = 50;
            this.puzzleName = ""; // TODO: What is this?
                                    // ^^ If I remember correctly this was for Duncan's
                                    // bounding box, so if the npc is within 50 of you
                                    // he will stop.

            this.x_hook = 0;
            this.y_hook = 0;

            this.elapsedTime = 0; // TODO: This tracks how fast it should animate - Dylan.
            this.image = new Image();
            this.image.src = src;
            //console.log(" " + src + "=" + this.image.height); // announce resource height

        /**
         * Renders this sprite (using the correct animation step previously "rolled").
         */
        this.render = function() {
            midctx.drawImage(this.image, this.srcX, this.srcY, this.dtx, this.dty,
                this.x - this.x_hook, this.y - this.y_hook, this.width, this.height);

        };
    };

    this.check_units = function() {
      var getEntityArray = g.entiteZones[g.currentZone.id]
      if (getEntityArray !== undefined) {
        var entitiesCount = getEntityArray.length;
      }
      for (var i = 0; i < entitiesCount; i++) {
          var entity = getEntityArray[i];
          if(entity.load) {
            entity.render();
            if(is_collide(entity, player)) {
              interactNPC = entity;
              return false;
            }
          }
      }
      return true;
    };

    this.movePlayer = function(clockTick) {

        /** Collision detection needs to consider the whole square the character occupies. */
        var x_leftmost = Math.floor(player.x/32);
        var x_rightmost = Math.floor((player.x + BOX_WIDTH) / 32); // + 32 is player width but 31 is smoother
        var y_upmost = Math.floor(player.y/32);
        var y_downmost = Math.floor((player.y + BOX_HEIGHT) / 32); // + 32 is height of player's box (ignores head collisions)

        var y_new_grid = 0; // tracks if moving player will cause them to enter new grid
        var x_new_grid = 0; // tracks if moving player will cause them to enter new grid

        var exit; // tracks if the player's movement has triggered an exit and zone change

        /** Checks which keys are being currently pressed and moves player if new location is valid. */
        if(W_KEY in keys || UP_KEY in keys) {
          // W
            this.spriteRoll(512, 8, clockTick, 0.1); // even if player doesn't move, animate them!

            /** Determine if moving the player will result in entering a new grid location. */
            y_new_grid = 0;
            // if player would enter new grid and that grid isn't offscreen
            if (Math.floor((player.y - this.speed) / 32) !== y_upmost &&
                           (y_upmost - 1 >= 0)) {
                y_new_grid =  1;
            }

            if ((player.y - (this.speed)) > 0) {
                /** Check that the player can move based on left AND right bounding box */
                if (sign_screen_bounds[y_upmost - y_new_grid][x_leftmost] === 0 &&
                    sign_screen_bounds[y_upmost - y_new_grid][x_rightmost] === 0) {
                    this.y -= this.speed;
                }


            } else { /** player is trying to move off screen, align them to edge if valid location. */
                if (sign_screen_bounds[0][x_leftmost] === 0 &&
                    sign_screen_bounds[0][x_rightmost] === 0) {
                    this.y = 1;
                }
            }

            /** Check for exits to the north. */
            if (sign_screen_bounds[y_upmost - y_new_grid][x_leftmost] === 2) {
               // console.log("EXIT FOUND");
                exit = g.currentZone.exits[x_leftmost + "," + (y_upmost - y_new_grid)];
            } else if (sign_screen_bounds[y_upmost - y_new_grid][x_rightmost] === 2) {
                exit = g.currentZone.exits[x_rightmost + "," + (y_upmost - y_new_grid)];
            }
        }

        if(S_KEY in keys || DOWN_KEY in keys) { // S
            this.spriteRoll(640, 8, clockTick, 0.1); // even if player doesn't move, animate them!

            /** Determine if moving the player will result in entering a new grid location*/
            y_new_grid = 0;
            // if player would enter new grid and that grid isn't offscreen
            if (Math.floor((player.y + BOX_HEIGHT + this.speed) / 32) !== y_downmost &&
                          ((y_downmost + 1) <= (sign_screen_bounds.length - 1))) {
                y_new_grid = 1;
            }

            /** If player would move off screen, move to edge instead, IF edge is a valid location */
            if ((player.y + BOX_HEIGHT + this.speed) < (background.image.height - 1)) { // "+32" player height no head
                /** Check that the player can move based on left AND right bounding box */
                if (sign_screen_bounds[y_downmost + y_new_grid][x_leftmost] === 0 &&
                    sign_screen_bounds[y_downmost + y_new_grid][x_rightmost] === 0) {
                    this.y += this.speed;
                }
            } else { /** player is trying to move off screen, align them to edge if valid location. */
                if (sign_screen_bounds[sign_screen_bounds.length - 1][x_leftmost] === 0 &&
                    sign_screen_bounds[sign_screen_bounds.length - 1][x_rightmost] === 0) {
                    this.y = (background.image.height - 1) - BOX_HEIGHT; // "-32" is height of player minus head
                }
            }

            /** Check for exits to the south. */
            if (sign_screen_bounds[y_downmost + y_new_grid][x_leftmost] === 2) {
                exit = g.currentZone.exits[x_leftmost + "," + (y_downmost + y_new_grid)];
            } else if (sign_screen_bounds[y_downmost + y_new_grid][x_rightmost] === 2) {
                exit = g.currentZone.exits[x_rightmost + "," + (y_downmost + y_new_grid)];
            }
        }

        if(A_KEY in keys || LEFT_KEY in keys) { // A
            this.spriteRoll(576, 8, clockTick, 0.1); // even if player doesn't move, animate them!

            /** Determine if moving the player will result in entering a new grid location*/
            x_new_grid = 0;
            // if player would enter new grid and that grid isn't offscreen
            if (Math.floor((player.x - this.speed) / 32) !== x_leftmost &&
                           (x_leftmost - 1 >= 0)) {
                x_new_grid = 1;
            }

            /** If player would move off screen, move to edge instead, IF edge is a valid location */
            if ((player.x - this.speed) > 0) {
                /** Check that the player can move based on top AND bottom bounding box */
                if (sign_screen_bounds[y_upmost][x_leftmost - x_new_grid] === 0 &&
                    sign_screen_bounds[y_downmost][x_leftmost - x_new_grid] === 0) {
                    this.x -= this.speed;
                }
            } else { /** player is trying to move off screen, align them to edge if valid location. */
                if (sign_screen_bounds[y_upmost][0] === 0 &&
                    sign_screen_bounds[y_downmost][0]) {
                    this.x = 0;
                }
            }

            /** Check for exits to the west. */
            if (sign_screen_bounds[y_upmost][x_leftmost - x_new_grid] === 2) {
                exit = g.currentZone.exits[(x_leftmost - x_new_grid) + "," + y_upmost];
            } else if (sign_screen_bounds[y_downmost][x_leftmost - x_new_grid] === 2) {
                exit = g.currentZone.exits[(x_leftmost - x_new_grid) + "," + y_downmost];
            }
        }

        if(D_KEY in keys || RIGHT_KEY in keys) { // D
            this.spriteRoll(704, 8, clockTick, 0.1); // even if player doesn't move, animate them!

            /** Determine if moving the player will result in entering a new grid location*/
            x_new_grid = 0;
            // if player would enter new grid and that grid isn't offscreen
            if (Math.floor((player.x + BOX_WIDTH + this.speed) / 32) !== x_rightmost &&
                          ((x_rightmost + 1) <= sign_screen_bounds[y_upmost].length - 1)) {
                x_new_grid = 1;
            }

            /** If player would move off screen, move to edge instead, IF edge is a valid location */
            if ((player.x + BOX_WIDTH + this.speed) < (background.image.width - 1)) { // "+32" is width of player
                /** Check that the player can move based on top AND bottom bounding box */
                if (sign_screen_bounds[y_upmost][x_rightmost + x_new_grid] === 0 &&
                    sign_screen_bounds[y_downmost][x_rightmost + x_new_grid] === 0) {
                    this.x += this.speed;
                }
            } else { /** player is trying to move off screen, align them to edge if valid location. */
                if (sign_screen_bounds[y_upmost][sign_screen_bounds[y_upmost].length - 1] === 0 &&
                    sign_screen_bounds[y_downmost][sign_screen_bounds[y_upmost].length - 1] === 0) {
                    this.x = (background.image.width - 1) - BOX_WIDTH; // "-32" is width of player
                }
            }

            /** Check for exits to the south. */
            if (sign_screen_bounds[y_upmost][x_rightmost + x_new_grid] === 2) {
                exit = g.currentZone.exits[(x_rightmost + x_new_grid) + "," + y_upmost];
            } else if (sign_screen_bounds[y_downmost][x_rightmost + x_new_grid] === 2) {
                exit = g.currentZone.exits[(x_rightmost + x_new_grid) + "," + y_downmost];
            }
        }

        /** Kirsten debug code */
        //if (Math.floor(oldx/32) !== Math.floor(this.x/32) ||
        //    Math.floor(oldy/32) !== Math.floor(this.y/32)) {
        //    console.log("(" + player.x + "," + player.y + ") [" +
        //    /**Math.floor*/(player.x / 32)  + " , " + /** Math.floor*/(player.y / 32) + "]");
        //}

        if (exit !== undefined) { // if an exit was found...
            g.loadZone(exit.go_to_zone, exit.x_entrance, exit.y_entrance);
        }

    };

    /**
     * This code is triggered when the interact button/key was pressed.
     */
    this.interact = function(interactNPC) {
      if(interactNPC.puzzleName === "Alden" && g.puzzleWins[0] === false) {
        g.currentPuzzle = uwetech.puzzle_alden;
      }

        /** Dylan/Duncan code. */
        //if(this.facing === "north") {
        //    var space = this.y * 32 + 32
        //} else if (this.facing === "south") {
        //    var space = this.y * 32 - 32
        //} else if (this.facing === "west") {
        //    var space = this.x * 32 + 32
        //} else {
        //    var space = this.x * 32 - 32
        //}
            /*
              Kirsten's Interaction Code
            */
        // /** Kirsten testing queued actions for multiple text pop-ups.*/
        //   if (npc_Alden.talking === undefined) {
        //       npc_Alden.talking = true;   // test code forces Alden to start talking.
        //   }
        //   if (npc_Alden.talking === true) { // queues up some dialog since Alden is talking.
        //     //console.log(npc_Alden.face); // kirsten test code
        //         g.queuedActions.push(function (){window.uwetech.dialog.show(
        //           "I am testing the word wrap functionality of the dialog.show method. If everything " +
        //           "works out, then this should word wrap in a very nice way. This box displays, at most, " +
        //           "four lines of text, with words being wrapped after 75 characters.", npc_Alden.face);});
        //     // kirsten test code
        //
        //       g.queuedActions.push(function (){window.uwetech.dialog.showRight(
        //           "This dialog box is for showing how queuedActions could work with multiple dialog " +
        //           "boxes you want to display in a series. I am also showing the functionality of" +
        //           "aligning a portrait to the right instead of the left. Neat huh?", npc_Alden.face);});
        //     // Of course, always make sure you call a dialog.hide() when you are done showing text!!
        //       g.queuedActions.push(function () {window.uwetech.dialog.hide();});
        //     //console.log(g.queuedActions[0]);
        //       npc_Alden.talking = false;
        //   } else if (npc_Alden.talking === false) {
        //     // test code to start alden talking again if the queue will be empty after this cycle.
        //       if (g.queuedActions.length <= 1) {
        //           npc_Alden.talking = true; // make him talk on next spacebar press
        //       }
        //   }


        if(interactNPC === undefined) {

        /** Kirsten testing queued actions for multiple text pop-ups.*/
          if (npc_Alden.talking === undefined) {
              npc_Alden.talking = true;   // test code forces Alden to start talking.
          }
          if (npc_Alden.talking === true) { // queues up some dialog since Alden is talking.
            //console.log(npc_Alden.face); // kirsten test code
            //    g.queuedActions.push(function (){window.uwetech.dialog.show(
            //      "You hear students in the distance having fun without you.", npc_Alden.face);});
            //// kirsten test code
            //
            //  g.queuedActions.push(function (){window.uwetech.dialog.showRight(
            //      "Maybe you should go talk to them.", npc_Alden.face);});
              g.queuedActions.push(function (){window.uwetech.dialog.showInner(
                  "You hear students in the distance having fun without you.");});
              // kirsten test code

              g.queuedActions.push(function (){window.uwetech.dialog.showInner(
                  "Maybe you should go talk to them.");});
            // Of course, always make sure you call a dialog.hide() when you are done showing text!!
              g.queuedActions.push(function () {window.uwetech.dialog.hide();});
            //console.log(g.queuedActions[0]);
              npc_Alden.talking = false;
          } else if (npc_Alden.talking === false) {
            // test code to start alden talking again if the queue will be empty after this cycle.
              if (g.queuedActions.length <= 1) {
                  npc_Alden.talking = true; // make him talk on next spacebar press
              }
          }
      } else {
        if (npc_Alden.talking === undefined) {
            npc_Alden.talking = true;   // test code forces Alden to start talking.
        }
        if (npc_Alden.talking === true) {
          var dialogSize = interactNPC.dialog.length;
          for(var i = 0; i < dialogSize; i++) {

            var text = interactNPC.dialog[i];
            var face = interactNPC.faceArray[i];
            var faceSpot = interactNPC.faceSpot;

            if(faceSpot === 0 ){
              g.queuedActions.push((function (text, face) {
                     return function () {
                         window.uwetech.dialog.showRight(text, face);
                     };
                  })(text, face));
            }
            if(faceSpot === 1) {
              g.queuedActions.push((function (text, face) {
                     return function () {
                         window.uwetech.dialog.show(text, face);
                     };
                  })(text, face));
            }

            console.log(text);
          }
          interactNPC.talkTo ^= true;
          g.queuedActions.push(function () {window.uwetech.dialog.hide();});
          npc_Alden.talking = false;
        } else if (npc_Alden.talking === false) {
          // test code to start alden talking again if the queue will be empty after this cycle.
            if (g.queuedActions.length <= 1) {
                npc_Alden.talking = true; // make him talk on next spacebar press
            }
        }
      }
        /** This logic will check if any actions are currently queued and pause the game.
         * Then the action at the front of the queue is called. If the action just called
         * results in the queue now being empty, the game is also un-paused. */
        if (g.queuedActions.length > 0 && g.queuedActions !== undefined) {
            g.isPaused = true;
            g.timer.isPaused = true;
            g.queuedActions.shift()();

            if (g.queuedActions.length === 0) {
                g.isPaused = false;
                g.timer.isPaused = false;
            }
        }


    };

    /**
     * TODO: Add comments about what spriteRoll is.
     * @param srY
     * @param maxLength
     * @param tick
     * @param frameDuration
     */
    this.spriteRoll = function(srY, maxLength, tick, frameDuration) {
        this.elapsedTime += tick;
        this.frameDuration = frameDuration;
        this.totalTime = frameDuration*maxLength;

        if ((this.elapsedTime >= this.totalTime)) {
          this.elapsedTime = 0;
        }

        this.srcY = srY;
        this.imgX += 1;



        this.srcX = this.dtx * Math.floor(this.elapsedTime / this.frameDuration);

        if (this.imgX >= maxLength) {
            this.imgX = 0;
        }
    };

    this.currentFrame = function () {
        return Math.floor(this.elapsedTime / this.frameDuration);
    };

    this.update = function() {

    };
};


/**
 * Kirsten's added this code for Background Object. This is really just to
 * render the background of a zone. I just didn't want it as part of the
 * Sprite code because it is so simple and doesn't really "do" stuff.
 */
var BackgroundObject = function() {
    this.load = false;

    this.srcX = 0;
    this.srcY = 0;
    this.dtx = btmcanvas.width;
    this.dty = btmcanvas.height;
    this.x = 0;
    this.y = 0;
    this.width = btmcanvas.width;
    this.height = btmcanvas.height;

    /**
     * Sets the current background to the passed Image object.
     * @param image_object
     */
    this.set = function(image_object) {
        this.image = image_object;

        this.renderBackground = function(xoffset, yoffset) {
            btmctx.drawImage(this.image, this.srcX + xoffset, this.srcY + yoffset,
                this.dtx, this.dty,
                this.x, this.y, this.width, this.height);
        };

        this.debugOn = function (xoffset, yoffset) {
            //btmctx.clearRect(0, 0, topcanvas.width, topcanvas.height);
            btmctx.font = "bold 16px sans-serif";
            btmctx.fillStyle = "#ff00ee";

            for (var y = Math.floor(yoffset / 32); y < sign_screen_bounds.length; y += 1) {
                for (var x = Math.floor(xoffset / 32); x < sign_screen_bounds[0].length; x += 1) {
                    var value = sign_screen_bounds[y][x];
                    btmctx.fillText(value,x * 32 - xoffset + 10,
                        32 + y * 32 - yoffset - 10);
                }
            }
        };
    };
};

var player = new Sprite();
var npc_Chin = new Sprite();
var npc_Alden = new Sprite();

var npc_Map1StairWalker = new Sprite();
var npc_Map1BottomWalker = new Sprite();
var npc_Map1dummyOne = new Sprite();
var npc_Map1dummyTwo = new Sprite();
var npc_Map1dummyThree = new Sprite();
var npc_Map1Blocker = new Sprite();

var npc_Map2Cashier = new Sprite();
var npc_Map2Bookman = new Sprite();

var npc_Map3BottomWalker = new Sprite();
var npc_Map3dummyOne = new Sprite();
var npc_Map3dummyTwo = new Sprite();
var npc_Map3dummyThree = new Sprite();
var npc_Map3dummyFour = new Sprite();
var npc_Map3dummyFive = new Sprite();
var npc_Map3dummySix = new Sprite();
var npc_Map3Jay = new Sprite();
var npc_Map3SilentBob = new Sprite();

var npc_Map4theChin = new Sprite();
var npc_Map4frontStudentOne = new Sprite();
var npc_Map4frontStudentTwo = new Sprite();
var npc_Map4middleStudentOne = new Sprite();
var npc_Map4middleStudentTwo = new Sprite();
var npc_Map4backStudentOne = new Sprite();

var npc_Map5dummyOne = new Sprite();
var npc_Map5dummyTwo = new Sprite();

var npc_Map6lib = new Sprite();

var npc_Map7dummyOne = new Sprite();
var npc_Map7dummyTwo = new Sprite();
var npc_Map7dummyThree = new Sprite();
var npc_Map7dummyFour = new Sprite();

var npc_Map8dummyOne = new Sprite();
var npc_Map8dummyTwo = new Sprite();
var npc_Map8dummyThree = new Sprite();
var npc_Map8dummyFour = new Sprite();

var npc_Map10dummyOne = new Sprite();
var npc_Map10dummyTwo = new Sprite();
var npc_Map10dummyThree = new Sprite();
var npc_Map10dummyFour = new Sprite();
var npc_Map10theAlden = new Sprite();
//var background = new Sprite();

// var alden_por = new Dialog();


// src, srcX, srcY, dtx, dty, x, y, width, height, speed

// NPC's
player.setOptions("./img/purple_orc.png", 0, 640, 64, 64,
                                    0, 0, 64, 64, 3);
//npc_Mobus.setOptions("./img/mobus.png", 0, 640, 64, 64, 350, 10, 62, 62, 1);

npc_Map1StairWalker.setOptions("./img/NPC/guyOne.png", 0, 140, 64, 64, 350,10, 62, 62, 1);
npc_Map1BottomWalker.setOptions("./img/NPC/spriteRobert.png", 0, 140, 64, 64, 300, 1020, 62, 62, 2);
npc_Map1Blocker.setOptions("./img/NPC/girlOne.png", 0, 140, 64, 64, 530, 141, 62, 62, 2);
npc_Map1dummyOne.setOptions("./img/NPC/girlOne.png", 0, 140, 64, 64, 100, 500, 62, 62, 2);
npc_Map1dummyTwo.setOptions("./img/NPC/monk.png", 0, 140, 64, 64, 150, 900, 62, 62, 2);
npc_Map1dummyThree.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 150, 150, 62, 62, 2);


npc_Map2Cashier.setOptions("./img/NPC/guyTwo.png", 0, 140, 64, 64, -15,155, 62, 62, 0);
npc_Map2Bookman.setOptions("./img/NPC/girlTwo.png", 0, 140, 64, 64, 430, 40, 62, 62, 0);

npc_Map3BottomWalker.setOptions("./img/NPC/monk.png", 0, 140, 64, 64, 900, 600, 62, 62, 2);
npc_Map3dummyOne.setOptions("./img/NPC/girlOne.png", 0, 140, 64, 64, 800, 150, 62, 62, 2);
npc_Map3dummyTwo.setOptions("./img/NPC/girlTwo.png", 0, 140, 64, 64, 750, 175, 62, 62, 2);
npc_Map3dummyThree.setOptions("./img/NPC/girlThree.png", 0, 140, 64, 64, 770, 135, 62, 62, 2);
npc_Map3dummyFour.setOptions("./img/NPC/girlThree.png", 0, 140, 64, 64, 900, 400, 62, 62, 2);
npc_Map3dummyFive.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 400, 500, 62, 62, 2);
npc_Map3dummySix.setOptions("./img/NPC/monk.png", 0, 140, 64, 64, 400, -20, 62, 62, 2);
npc_Map3Jay.setOptions("./img/NPC/guyTwo.png", 0, 140, 64, 64, 90, 180, 62, 62, 2);
npc_Map3SilentBob.setOptions("./img/NPC/guyThree.png", 0, 140, 64, 64, 50, 180, 62, 62, 2);

npc_Map4theChin.setOptions("./img/NPC/chin.png", 0, 140, 64, 64, 515,20, 62, 62, 0);
npc_Map4frontStudentOne.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 440,20, 62, 62, 0);
npc_Map4frontStudentTwo.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 440,100, 62, 62, 0);
npc_Map4middleStudentOne.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 370,20, 62, 62, 0);
npc_Map4middleStudentTwo.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 370,100, 62, 62, 0);
npc_Map4backStudentOne.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 250,100, 62, 62, 0);

npc_Map5dummyOne.setOptions("./img/NPC/chin.png", 0, 140, 64, 64, 110,260, 62, 62, 0);
npc_Map5dummyTwo.setOptions("./img/NPC/chin.png", 0, 140, 64, 64, 20,20, 62, 62, 0);

npc_Map6lib.setOptions("./img/NPC/chin.png", 0, 140, 64, 64, 150,145, 62, 62, 0);

npc_Map7dummyOne.setOptions("./img/NPC/girlOne.png", 0, 140, 64, 64, 50, 700, 62, 62, 2);
npc_Map7dummyTwo.setOptions("./img/NPC/girlTwo.png", 0, 140, 64, 64, 170, 200, 62, 62, 2);
npc_Map7dummyThree.setOptions("./img/NPC/girlThree.png", 0, 140, 64, 64, 350, 580, 62, 62, 2);
npc_Map7dummyFour.setOptions("./img/NPC/monk.png", 0, 140, 64, 64, 150, 200, 62, 62, 2);

npc_Map8dummyOne.setOptions("./img/NPC/girlOne.png", 0, 140, 64, 64, 50, 700, 62, 62, 2);
npc_Map8dummyTwo.setOptions("./img/NPC/girlTwo.png", 0, 140, 64, 64, 150, 0, 62, 62, 2);
npc_Map8dummyThree.setOptions("./img/NPC/girlThree.png", 0, 140, 64, 64, 350, 580, 62, 62, 2);
npc_Map8dummyFour.setOptions("./img/NPC/monk.png", 0, 140, 64, 64, 500, 900, 62, 62, 2);

npc_Map10dummyOne.setOptions("./img/NPC/girlOne.png", 0, 140, 64, 64, 210, 260, 62, 62, 2);
npc_Map10dummyTwo.setOptions("./img/NPC/girlTwo.png", 0, 140, 64, 64, 340, 260, 62, 62, 2);
npc_Map10dummyThree.setOptions("./img/NPC/girlThree.png", 0, 140, 64, 64, 210, 180, 62, 62, 2);
npc_Map10dummyFour.setOptions("./img/NPC/monk.png", 0, 140, 64, 64, 340, 180, 62, 62, 2);
npc_Map10theAlden.setOptions("./img/NPC/alden.png", 0, 140, 64, 64, 530, 170, 62, 62, 2);

npc_Map10theAlden.puzzleName = "Alden";

npc_Alden.face = (function () {
    var temp = new Image();
    temp.src =  "./img/Alden-plain.png";
    return temp;
})();
console.log(npc_Alden.face);

//Faces
// alden_por.setOptions("./img/Alden-plain.png", 0, 0, 480, 638, 100, 100, 480, 638);

var background = new BackgroundObject();
var initialBackground = new Image();
initialBackground.src = "./img/ext_stairs_lower.jpg";
background.set(initialBackground);

var grid = new BackgroundObject();
var gridimage = new Image();
gridimage.src = "./img/32x32grid.png";
grid.set(gridimage);

npc_Map1StairWalker.image.onload = function() {
  npc_Map1StairWalker.load = true;
  npc_Map1Blocker.load = true;
  npc_Map1BottomWalker.load = true;
  npc_Map1dummyOne.load = true;
  npc_Map1dummyTwo.load = true;
  npc_Map1dummyThree.load = true;

  npc_Map2Cashier.load = true;
  npc_Map2Bookman.load = true;

  npc_Map3BottomWalker.load = true;
  npc_Map3dummyOne.load = true;
  npc_Map3dummyTwo.load = true;
  npc_Map3dummyThree.load = true;
  npc_Map3dummyFour.load = true;
  npc_Map3dummyFive.load = true;
  npc_Map3dummySix.load = true;
  npc_Map3Jay.load = true;
  npc_Map3SilentBob.load = true;

  npc_Map4theChin.load = true;
  npc_Map4frontStudentOne.load = true;
  npc_Map4frontStudentTwo.load = true;
  npc_Map4middleStudentOne.load = true;
  npc_Map4middleStudentTwo.load = true;
  npc_Map4backStudentOne.load = true;

  npc_Map5dummyOne.load = true;
  npc_Map5dummyTwo.load = true;

  npc_Map6lib.load = true;

  npc_Map7dummyOne.load = true;
  npc_Map7dummyTwo.load = true;
  npc_Map7dummyThree.load = true;
  npc_Map7dummyFour.load = true;

  npc_Map8dummyOne.load = true;
  npc_Map8dummyTwo.load = true;
  npc_Map8dummyThree.load = true;
  npc_Map8dummyFour.load = true;

  npc_Map10dummyOne.load = true;
  npc_Map10dummyTwo.load = true;
  npc_Map10dummyThree.load = true;
  npc_Map10dummyFour.load = true;
  npc_Map10theAlden.load = true;

};

/*
Map1(bottomStaircase) Npc update functions are below
Blocker - If the player gets close he block you from going around.
Stairwalker - Walks up and down the stairs.. like a normal person.
BottomWalker - Walks left to right at the bottom of the stairs.. like a normal person.
*/
npc_Map1StairWalker.dialog[0] = "I feel so animated! Running up! Running down!";
npc_Map1StairWalker.dialog[1] = "Up down, up down! Whoo, such an animated feeling!";

npc_Map1dummyTwo.dialog[0] = "Can you direct me to WCG?  I'm looking for Dr. Chinn.  He's lost his marbles...or was it spilled his fruit."
npc_Map1dummyTwo.dialog[1] = "Anyway, he needs some help solving this mystery.  I heard he gives easy A's."

npc_Map1dummyOne.dialog[0] = "Do you know where the Science Building is?  <NAME> is up there exposing the inner workings of something called..."
npc_Map1dummyOne.dialog[1] = "computers, yeah that's it.  I heard there's a secret code to solving his puzzle."

npc_Map1dummyThree.dialog[0] = "<NAME> is over in Cherry Parks.  He said my code is...how did he put it..."
npc_Map1dummyThree.dialog[1] = "'Your code is strange and unexpected. It is full of bugs.  Debug them if you can'"

npc_Map1BottomWalker.dialog[0] = "This stream of cars is never ending and the walk sign won't change! " +
                                 "I'll never be able to cross. I suggest you don't try either!";
npc_Map1BottomWalker.faceArray[0] = npc_Map1BottomWalker.face;
npc_Map1BottomWalker.face.src =  "./img/Robert.png";
npc_Map1StairWalker.face.src =  "./img/Alden-plain.png";

npc_Map1Blocker.update = function(clockTick) {
  //console.log(this.talkTo);
  if(this.talkTo) {
    npc_Map1Blocker.dialog[0] = "Just go around me, why dontcha?";
  }
  if(!this.talkTo) {
    npc_Map1Blocker.dialog[0] = "Would you mind not blocking my path?";
  }
  if(player.y < 171) {
    if(W_KEY in keys || UP_KEY in keys) {
      this.spriteRoll(512, 8,  clockTick, 0.1);
      this.y = (player.y - 30);
    }
    if(S_KEY in keys || DOWN_KEY in keys) {
      this.spriteRoll(640, 8,  clockTick, 0.1);
      this.y = (player.y - 30);
    }
  }
};
npc_Map1dummyOne.update = function(clockTick) {
};
npc_Map1dummyTwo.update = function(clockTick) {
};
npc_Map1dummyThree.update = function(clockTick) {
};


var chinFlip = 0;
var chinCounter = 0;
var chinDirection = 0;

npc_Map1StairWalker.update = function(clockTick) {
  //console.log(player.y);
  //Checks to see if you are next to chin
  if(is_collide(this, player) && chinCounter === 0) {
    chinDirection = chinFlip;
    chinFlip = 3;
    chinCounter = 1;
  }

  //If you are next to chin then this happens.
  if(chinFlip === 3) {
    this.y += 0;
    if(chinDirection === 0) {
      this.spriteRoll(640, 1,  clockTick, 0.5);

    }
    if(chinDirection === 1) {
      this.spriteRoll(512, 1, clockTick, 0.5);
    }
    if(!is_collide(this, player)) {

      chinFlip = chinDirection;
    }
  }

  // You are not next to chin and he is walking south
  if(chinFlip === 0) {
    chinCounter = 0;
    this.spriteRoll(640, 8,  clockTick, 0.1);
    this.y += this.speed;

    if(this.y >= 700) {
      chinFlip = 1;
    }

  }

  // You are not next to chin and he is walking north
  if(chinFlip === 1) {
    chinCounter = 0;
    this.spriteRoll(512, 8, clockTick, 0.1);
    this.y -= this.speed;

    if(this.y <= 10) {
      chinFlip = 0;
    }
  }
};


var aldenFlip = 0;
var aldenCounter = 0;
var aldenDirection = 0;
npc_Map1BottomWalker.update = function(clockTick) {

  var aldenX = Math.floor(this.x/32) + 1;
  var aldenY = Math.floor(this.y/32) + 1

  //Checks to see if you are next to alden
  if(is_collide(this, player) && aldenCounter === 0) {
    aldenDirection = aldenFlip;
    aldenFlip = 3;
    aldenCounter = 1;
  }

  //If you are next to alden then this happens.
  if(aldenFlip === 3) {
    this.y += 0;
    if(aldenDirection === 0) {
      this.spriteRoll(704, 1,  clockTick, 0.5);

    }
    if(aldenDirection === 1) {
      this.spriteRoll(576, 1, clockTick, 0.5);

    }
    if(!is_collide(this, player)) {

      aldenFlip = aldenDirection;
    }
  }

  // You are not next to alden and he is walking west
  if(aldenFlip === 0) {
    aldenCounter = 0;
    this.spriteRoll(704, 8,  clockTick, 0.1);
    this.x += this.speed;

    if(this.x >= 450) {
      aldenFlip = 1;
    }

  }
  // You are not next to alden and he is walking east
  if(aldenFlip === 1) {
    aldenCounter = 0;
    this.spriteRoll(576, 8,  clockTick, 0.1);
    this.x -= this.speed;

    if(this.x <= 10) {
      aldenFlip = 0;
    }
  }
};

/*
Map2(BookStore) Npc update functions are below
Bookman - If the player gets close he looks for a book.
Cashier - If the player gets close he will check you out. *wink*
*/
npc_Map2Bookman.dialog[0] = "<NAME> taught me that a monkey can peel a Banana in O(log n) time.  That's pretty fast."
npc_Map2Bookman.update = function(clockTick) {
  //console.log(dist);
  if(is_collide(this, player)) {
    this.spriteRoll(780, 5,  clockTick, 0.3);
  } else {
    this.spriteRoll(780, 1,  clockTick, 0.3);
  }

};
npc_Map2Cashier.update = function(clockTick) {
  //console.log(dist);
  if(is_collide(this, player)) {
    this.spriteRoll(460, 8,  clockTick, 0.3);
  } else {
    this.spriteRoll(460, 1,  clockTick, 0.3);
  }

};

/*
Map3(walkWay) Npc update functions are below
dummyGroup - Just a bunch of friends talking and blocking the way.
dummyOne - the one on the far right
dummyTwo - the one furthest south
dummyThree - the one furthest north
bottomWalker - Walks left to right at the bottom of the stairs.. like a normal person.
*/

npc_Map3dummyOne.dialog[0] = "...and then I said...";
npc_Map3dummyOne.dialog[1] = "Would you mind? We are having a conversation about some cute boys.";
npc_Map3dummyOne.update = function(clockTick) {
  this.spriteRoll(576, 1,  clockTick, 0.1);
};
npc_Map3dummyTwo.dialog[0] = "Did he really say that?";
npc_Map3dummyTwo.update = function(clockTick) {
  this.spriteRoll(512, 1,  clockTick, 0.1);
};
npc_Map3dummyThree.dialog[0] = "He sounds so dreamy.";
npc_Map3dummyThree.update = function(clockTick) {
  this.spriteRoll(900, 1,  clockTick, 0.1);
};
npc_Map3dummyFour.dialog[0] = "la, la, la, 867-5309. What was the rest of the song!?";
npc_Map3dummyFour.dialog[1] = "That number would make an awesome secret code though.";
npc_Map3dummyFour.update = function(clockTick) {
  this.spriteRoll(900, 1,  clockTick, 0.1);
};

npc_Map3dummyFive.update = function(clockTick) {
  if(this.talkTo) {
    this.spriteRoll(704, 8,  clockTick, 0.1);
    this.x += this.speed;
  }
  if(!this.talkTo) {
    this.spriteRoll(900, 1,  clockTick, 0.1);
    npc_Map3dummyFive.dialog[0] = "Wait, when does this happen? Now?"
    npc_Map3dummyFive.dialog[1] = "You mean what I’m doing now is actually happening right now?"
  }
};
npc_Map3dummySix.dialog[0] = "Have you seen that girl known as Jenny?"
npc_Map3dummySix.dialog[1] = "I hear her song is really catchy."
npc_Map3dummySix.update = function(clockTick) {
  this.spriteRoll(900, 1,  clockTick, 0.1);
};

// Kirsten and Loren veto'd cussing. We found a different jay/silent bob quote.
npc_Map3Jay.face.src =  "./img/Robert.png";
npc_Map3Jay.dialog[0] = "See those two over there? Yeah, they had a Star Wars themed wedding. ";
npc_Map3Jay.dialog[1] = ".......";
npc_Map3Jay.dialog[2] = "AND they tied the knot dressed as Storm Troopers!";
npc_Map3Jay.faceArray[0] = npc_Map3Jay.face;
npc_Map3Jay.faceArray[1] = npc_Map3SilentBob.face;
npc_Map3Jay.faceArray[2] = npc_Map3Jay.face;

npc_Map3SilentBob.faceSpot = 1;
npc_Map3SilentBob.face.src =  "./img/Alden-plain.png";
npc_Map3SilentBob.dialog[0] = "See those two over there? Yeah, they had a Star Wars themed wedding. ";
npc_Map3SilentBob.dialog[1] = ".......";
npc_Map3SilentBob.dialog[2] = "AND they tied the knot dressed as Storm Troopers!";
npc_Map3SilentBob.faceArray[0] = npc_Map3Jay.face;
npc_Map3SilentBob.faceArray[1] = npc_Map3SilentBob.face;
npc_Map3SilentBob.faceArray[2] = npc_Map3Jay.face;


npc_Map3Jay.update = function(clockTick) {
  this.spriteRoll(900, 1,  clockTick, 0.1);
};


npc_Map3SilentBob.update = function(clockTick) {
  this.spriteRoll(900, 1,  clockTick, 0.1);
}
npc_Map3BottomWalker.dialog[0] = "Sunnyside is a place of ruin and despair, ruled by an evil bear who smells of strawberries!"
npc_Map3BottomWalker.update = function(clockTick) {<commit_msg>People have faces<commit_after>// Relate animation drawing to window frame rate
window.requestAnimFrame = (function () {
    return window.requestAnimationFrame  ||
        window.webkitRequestAnimationFrame ||
        window.mozRequestAnimationFrame    ||
          function (callback) {
            window.setTimeout(callback, 1000 / 60);
        };
}());

/** NOT for animations/movement! This is strictly for single key press logic. */
window.addEventListener('keydown', function (e) {
    if (g.currentPuzzle === undefined) {
        //console.log("no puzzle");
        g.handleKeyDownEvent(e.keyCode);
    } else {
        //console.log("yes puzzle");
        // TODO: do puzzles want to hear key events??
        //g.currentPuzzle.handleKeyDownEvent(e.keyCode);
    }
});

window.addEventListener('keyup', function (e) {
    if (g.currentPuzzle === undefined) {
        g.handleKeyUpEvent(e.keyCode);
    } else {
        // TODO: do puzzles want to hear key events??
        //g.currentPuzzle.handleKeyUpEvent(e.keyCode);
    }
});

/** Array containing all currently pressed keys. This is for animations/movement. */
var keys = window.uwetech.Input.keys; // code is in input.js

var BOX_WIDTH = 29; // width of the player bounding box for collisions
var BOX_HEIGHT = 24; // height of the player bounding box for collisions

//  constants!     W 87, S 83, A 65, D 68, space 32
var W_KEY = 87;
var S_KEY = 83;
var A_KEY = 65;
var D_KEY = 68;
var P_KEY = 80;
var LEFT_KEY  = 37;
var UP_KEY    = 38;
var RIGHT_KEY = 39;
var DOWN_KEY  = 40;
var ENTER_KEY = 13;
var SPACE_KEY = 32;
var DEBUG_KEY = 192;  // ` key ~ key  is the debug key

/** Bottom canvas is for the background. NO ANIMATIONS. */
var btmcanvas = document.getElementById('bottomlayer'),
    btmctx = btmcanvas.getContext('2d');

/** Middle canvas is for drawing sprites & other animated stuff. */
var midcanvas = document.getElementById('middlelayer'),
    midctx = midcanvas.getContext('2d');

/** Top canvas will draw on top of bottom and middle canvas. */
var topcanvas = document.getElementById('toplayer'),
    topctx = topcanvas.getContext('2d');

/** Loading screen canvas, or something. */
var loadcanvas = document.getElementById('loadlayer'),
    loadctx = loadcanvas.getContext('2d');

/** Loading screen canvas, or something. */
var timercanvas = document.getElementById('timerlayer'),
    timerctx = timercanvas.getContext('2d');

/** BTW: Other canvases exist you don't know about are in the HTML file. */

/** Represents the 2D array for the zone's boundaries.
 *  0 == walkable space
 *  1 == non walkable space
 *  2 == exit exists here
 *  ___ == ????
 */
var sign_screen_bounds = null;

// Keeps the player in bounds -- Kirsten update: no longer being used.
var math = function() {
  this.clamp = function(i, min, max) {
    return Math.max(Math.min(i, max),min);
  };
};
// TODO: What is this for?
function distance(a, b) {
    var dx = a.x - b.x;
    var dy = a.y - b.y;
    return Math.sqrt(dx * dx + dy * dy);
}

//http://stackoverflow.com/questions/306316/determine-if-two-rectangles-overlap-each-other
function is_collide(a, b) {

  var ax_1 = a.x - 15;
  var ax_2 = a.x + BOX_WIDTH + 45; // + 32 is player width but 31 is smoother
  var ay_1 = a.y + 10;
  var ay_2 = a.y + BOX_HEIGHT + 70; // + 32 is height of player's box (ignores head collisions)

  var bx_1 = b.x;
  var bx_2 = b.x + BOX_WIDTH; // + 32 is player width but 31 is smoother
  var by_1 = b.y;
  var by_2 = b.y + BOX_HEIGHT;

  return (ax_1 < bx_2 && ax_2 > bx_1 && ay_1 < by_2 && ay_2 > by_1);
}

/**
 *  The camera will control what part of a map we're viewing and where
 *  the entities will be drawn on screen relative to current camera view
 * @constructor
 */
var Camera = function () {
    /**
     * Recalculate camera position based entirely on the passed
     * entity's x and y location. (entity should be player!!)
     *
     * Requires background.image.width/height and midcanvas.width/height
     * to determine edges of map and center the player correctly.
     * @param entity Should be player.
     */
    this.setup = function(entity) {
          //this.x = (canvas.width / 2) - entity.x;
          //this.y = (canvas.height / 2) - entity.y;

          // these variables determine where the camera starts
          this.x = (midcanvas.width / 2) - entity.x;
          this.y = (midcanvas.height / 2) - entity.y;

          // these if elseif blocks prevent the camera from moving
          // off the edge of the map

          // if the right side of the camera would go off the side...
          if (entity.x + (midcanvas.width / 2) > background.image.width) {
            // set it to the rightmost legal position
            this.x = midcanvas.width - background.image.width;
          } // if the left side would go off...
          else if(entity.x - (midcanvas.width / 2) < 0) {
            // set it to the leftmost legal position
            this.x = 0;
          }
          // if the top of the camera would scroll off
          if (entity.y - (midcanvas.height / 2) < 0 ) {
              // set it to the bottommost legal position
              this.y = 0;
            } // if the bottom of the camera would scroll off
            else if((midcanvas.height / 2) + entity.y > background.image.height) {
              // set it to the topmost legal position
              this.y = midcanvas.height - background.image.height;
            }
    };

    /**
     * Currently redirects to setup(), as the calculation is the same.
     * @param entity Should be the player.
     */
      this.getPosition = function (entity) {
          this.setup(entity);
      };
      //    function(entity) {
      //  this.x = (canvas.width / 2) - entity.x;
      //  this.y = (canvas.height / 2) - entity.y;
      //};
};

/**
 * Creates a new sprite. What is a sprite? A sprite is an object that has a visual
 * representation (spritesheet image), has a location in the world (x, y). Some
 * sprites may have additional functionality (ex: player sprites have speed).
 * @constructor
 */
var Sprite = function() {
    this.load = false;
    this.imgX = 0; // TODO: What is imgX for?

    /**
     * Lots of parameter options! Yay! Seriously though, most of these parameters are
     * needed to draw the image for this sprite correctly.
     */
    this.setOptions = function(src, srcX, srcY, dtx, dty, x, y, width, height, speed) {
            this.srcX = srcX;
            this.srcY = srcY;
            this.dtx = dtx;
            this.dty = dty;
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
            this.speed = speed;
           // this.facing = "south";
            this.dialog = [];
            this.talkTo = false;
            this.faceSpot = 0;// Used to check if you want the dialog on left or right
                                // O is left 1 is right
            this.faceArray = []; // Used to check which face you want to show
            this.face = new Image();
            this.visualRadius = 50;
            this.puzzleName = ""; // TODO: What is this?
                                    // ^^ If I remember correctly this was for Duncan's
                                    // bounding box, so if the npc is within 50 of you
                                    // he will stop.

            this.x_hook = 0;
            this.y_hook = 0;

            this.elapsedTime = 0; // TODO: This tracks how fast it should animate - Dylan.
            this.image = new Image();
            this.image.src = src;
            //console.log(" " + src + "=" + this.image.height); // announce resource height

        /**
         * Renders this sprite (using the correct animation step previously "rolled").
         */
        this.render = function() {
            midctx.drawImage(this.image, this.srcX, this.srcY, this.dtx, this.dty,
                this.x - this.x_hook, this.y - this.y_hook, this.width, this.height);

        };
    };

    this.check_units = function() {
      var getEntityArray = g.entiteZones[g.currentZone.id]
      if (getEntityArray !== undefined) {
        var entitiesCount = getEntityArray.length;
      }
      for (var i = 0; i < entitiesCount; i++) {
          var entity = getEntityArray[i];
          if(entity.load) {
            entity.render();
            if(is_collide(entity, player)) {
              interactNPC = entity;
              return false;
            }
          }
      }
      return true;
    };

    this.movePlayer = function(clockTick) {

        /** Collision detection needs to consider the whole square the character occupies. */
        var x_leftmost = Math.floor(player.x/32);
        var x_rightmost = Math.floor((player.x + BOX_WIDTH) / 32); // + 32 is player width but 31 is smoother
        var y_upmost = Math.floor(player.y/32);
        var y_downmost = Math.floor((player.y + BOX_HEIGHT) / 32); // + 32 is height of player's box (ignores head collisions)

        var y_new_grid = 0; // tracks if moving player will cause them to enter new grid
        var x_new_grid = 0; // tracks if moving player will cause them to enter new grid

        var exit; // tracks if the player's movement has triggered an exit and zone change

        /** Checks which keys are being currently pressed and moves player if new location is valid. */
        if(W_KEY in keys || UP_KEY in keys) {
          // W
            this.spriteRoll(512, 8, clockTick, 0.1); // even if player doesn't move, animate them!

            /** Determine if moving the player will result in entering a new grid location. */
            y_new_grid = 0;
            // if player would enter new grid and that grid isn't offscreen
            if (Math.floor((player.y - this.speed) / 32) !== y_upmost &&
                           (y_upmost - 1 >= 0)) {
                y_new_grid =  1;
            }

            if ((player.y - (this.speed)) > 0) {
                /** Check that the player can move based on left AND right bounding box */
                if (sign_screen_bounds[y_upmost - y_new_grid][x_leftmost] === 0 &&
                    sign_screen_bounds[y_upmost - y_new_grid][x_rightmost] === 0) {
                    this.y -= this.speed;
                }


            } else { /** player is trying to move off screen, align them to edge if valid location. */
                if (sign_screen_bounds[0][x_leftmost] === 0 &&
                    sign_screen_bounds[0][x_rightmost] === 0) {
                    this.y = 1;
                }
            }

            /** Check for exits to the north. */
            if (sign_screen_bounds[y_upmost - y_new_grid][x_leftmost] === 2) {
               // console.log("EXIT FOUND");
                exit = g.currentZone.exits[x_leftmost + "," + (y_upmost - y_new_grid)];
            } else if (sign_screen_bounds[y_upmost - y_new_grid][x_rightmost] === 2) {
                exit = g.currentZone.exits[x_rightmost + "," + (y_upmost - y_new_grid)];
            }
        }

        if(S_KEY in keys || DOWN_KEY in keys) { // S
            this.spriteRoll(640, 8, clockTick, 0.1); // even if player doesn't move, animate them!

            /** Determine if moving the player will result in entering a new grid location*/
            y_new_grid = 0;
            // if player would enter new grid and that grid isn't offscreen
            if (Math.floor((player.y + BOX_HEIGHT + this.speed) / 32) !== y_downmost &&
                          ((y_downmost + 1) <= (sign_screen_bounds.length - 1))) {
                y_new_grid = 1;
            }

            /** If player would move off screen, move to edge instead, IF edge is a valid location */
            if ((player.y + BOX_HEIGHT + this.speed) < (background.image.height - 1)) { // "+32" player height no head
                /** Check that the player can move based on left AND right bounding box */
                if (sign_screen_bounds[y_downmost + y_new_grid][x_leftmost] === 0 &&
                    sign_screen_bounds[y_downmost + y_new_grid][x_rightmost] === 0) {
                    this.y += this.speed;
                }
            } else { /** player is trying to move off screen, align them to edge if valid location. */
                if (sign_screen_bounds[sign_screen_bounds.length - 1][x_leftmost] === 0 &&
                    sign_screen_bounds[sign_screen_bounds.length - 1][x_rightmost] === 0) {
                    this.y = (background.image.height - 1) - BOX_HEIGHT; // "-32" is height of player minus head
                }
            }

            /** Check for exits to the south. */
            if (sign_screen_bounds[y_downmost + y_new_grid][x_leftmost] === 2) {
                exit = g.currentZone.exits[x_leftmost + "," + (y_downmost + y_new_grid)];
            } else if (sign_screen_bounds[y_downmost + y_new_grid][x_rightmost] === 2) {
                exit = g.currentZone.exits[x_rightmost + "," + (y_downmost + y_new_grid)];
            }
        }

        if(A_KEY in keys || LEFT_KEY in keys) { // A
            this.spriteRoll(576, 8, clockTick, 0.1); // even if player doesn't move, animate them!

            /** Determine if moving the player will result in entering a new grid location*/
            x_new_grid = 0;
            // if player would enter new grid and that grid isn't offscreen
            if (Math.floor((player.x - this.speed) / 32) !== x_leftmost &&
                           (x_leftmost - 1 >= 0)) {
                x_new_grid = 1;
            }

            /** If player would move off screen, move to edge instead, IF edge is a valid location */
            if ((player.x - this.speed) > 0) {
                /** Check that the player can move based on top AND bottom bounding box */
                if (sign_screen_bounds[y_upmost][x_leftmost - x_new_grid] === 0 &&
                    sign_screen_bounds[y_downmost][x_leftmost - x_new_grid] === 0) {
                    this.x -= this.speed;
                }
            } else { /** player is trying to move off screen, align them to edge if valid location. */
                if (sign_screen_bounds[y_upmost][0] === 0 &&
                    sign_screen_bounds[y_downmost][0]) {
                    this.x = 0;
                }
            }

            /** Check for exits to the west. */
            if (sign_screen_bounds[y_upmost][x_leftmost - x_new_grid] === 2) {
                exit = g.currentZone.exits[(x_leftmost - x_new_grid) + "," + y_upmost];
            } else if (sign_screen_bounds[y_downmost][x_leftmost - x_new_grid] === 2) {
                exit = g.currentZone.exits[(x_leftmost - x_new_grid) + "," + y_downmost];
            }
        }

        if(D_KEY in keys || RIGHT_KEY in keys) { // D
            this.spriteRoll(704, 8, clockTick, 0.1); // even if player doesn't move, animate them!

            /** Determine if moving the player will result in entering a new grid location*/
            x_new_grid = 0;
            // if player would enter new grid and that grid isn't offscreen
            if (Math.floor((player.x + BOX_WIDTH + this.speed) / 32) !== x_rightmost &&
                          ((x_rightmost + 1) <= sign_screen_bounds[y_upmost].length - 1)) {
                x_new_grid = 1;
            }

            /** If player would move off screen, move to edge instead, IF edge is a valid location */
            if ((player.x + BOX_WIDTH + this.speed) < (background.image.width - 1)) { // "+32" is width of player
                /** Check that the player can move based on top AND bottom bounding box */
                if (sign_screen_bounds[y_upmost][x_rightmost + x_new_grid] === 0 &&
                    sign_screen_bounds[y_downmost][x_rightmost + x_new_grid] === 0) {
                    this.x += this.speed;
                }
            } else { /** player is trying to move off screen, align them to edge if valid location. */
                if (sign_screen_bounds[y_upmost][sign_screen_bounds[y_upmost].length - 1] === 0 &&
                    sign_screen_bounds[y_downmost][sign_screen_bounds[y_upmost].length - 1] === 0) {
                    this.x = (background.image.width - 1) - BOX_WIDTH; // "-32" is width of player
                }
            }

            /** Check for exits to the south. */
            if (sign_screen_bounds[y_upmost][x_rightmost + x_new_grid] === 2) {
                exit = g.currentZone.exits[(x_rightmost + x_new_grid) + "," + y_upmost];
            } else if (sign_screen_bounds[y_downmost][x_rightmost + x_new_grid] === 2) {
                exit = g.currentZone.exits[(x_rightmost + x_new_grid) + "," + y_downmost];
            }
        }

        /** Kirsten debug code */
        //if (Math.floor(oldx/32) !== Math.floor(this.x/32) ||
        //    Math.floor(oldy/32) !== Math.floor(this.y/32)) {
        //    console.log("(" + player.x + "," + player.y + ") [" +
        //    /**Math.floor*/(player.x / 32)  + " , " + /** Math.floor*/(player.y / 32) + "]");
        //}

        if (exit !== undefined) { // if an exit was found...
            g.loadZone(exit.go_to_zone, exit.x_entrance, exit.y_entrance);
        }

    };

    /**
     * This code is triggered when the interact button/key was pressed.
     */
    this.interact = function(interactNPC) {
      if(interactNPC.puzzleName === "Alden" && g.puzzleWins[0] === false) {
        g.currentPuzzle = uwetech.puzzle_alden;
      }

        /** Dylan/Duncan code. */
        //if(this.facing === "north") {
        //    var space = this.y * 32 + 32
        //} else if (this.facing === "south") {
        //    var space = this.y * 32 - 32
        //} else if (this.facing === "west") {
        //    var space = this.x * 32 + 32
        //} else {
        //    var space = this.x * 32 - 32
        //}
            /*
              Kirsten's Interaction Code
            */
        // /** Kirsten testing queued actions for multiple text pop-ups.*/
        //   if (npc_Alden.talking === undefined) {
        //       npc_Alden.talking = true;   // test code forces Alden to start talking.
        //   }
        //   if (npc_Alden.talking === true) { // queues up some dialog since Alden is talking.
        //     //console.log(npc_Alden.face); // kirsten test code
        //         g.queuedActions.push(function (){window.uwetech.dialog.show(
        //           "I am testing the word wrap functionality of the dialog.show method. If everything " +
        //           "works out, then this should word wrap in a very nice way. This box displays, at most, " +
        //           "four lines of text, with words being wrapped after 75 characters.", npc_Alden.face);});
        //     // kirsten test code
        //
        //       g.queuedActions.push(function (){window.uwetech.dialog.showRight(
        //           "This dialog box is for showing how queuedActions could work with multiple dialog " +
        //           "boxes you want to display in a series. I am also showing the functionality of" +
        //           "aligning a portrait to the right instead of the left. Neat huh?", npc_Alden.face);});
        //     // Of course, always make sure you call a dialog.hide() when you are done showing text!!
        //       g.queuedActions.push(function () {window.uwetech.dialog.hide();});
        //     //console.log(g.queuedActions[0]);
        //       npc_Alden.talking = false;
        //   } else if (npc_Alden.talking === false) {
        //     // test code to start alden talking again if the queue will be empty after this cycle.
        //       if (g.queuedActions.length <= 1) {
        //           npc_Alden.talking = true; // make him talk on next spacebar press
        //       }
        //   }


        if(interactNPC === undefined) {

        /** Kirsten testing queued actions for multiple text pop-ups.*/
          if (npc_Alden.talking === undefined) {
              npc_Alden.talking = true;   // test code forces Alden to start talking.
          }
          if (npc_Alden.talking === true) { // queues up some dialog since Alden is talking.
            //console.log(npc_Alden.face); // kirsten test code
            //    g.queuedActions.push(function (){window.uwetech.dialog.show(
            //      "You hear students in the distance having fun without you.", npc_Alden.face);});
            //// kirsten test code
            //
            //  g.queuedActions.push(function (){window.uwetech.dialog.showRight(
            //      "Maybe you should go talk to them.", npc_Alden.face);});
              g.queuedActions.push(function (){window.uwetech.dialog.showInner(
                  "You hear students in the distance having fun without you.");});
              // kirsten test code

              g.queuedActions.push(function (){window.uwetech.dialog.showInner(
                  "Maybe you should go talk to them.");});
            // Of course, always make sure you call a dialog.hide() when you are done showing text!!
              g.queuedActions.push(function () {window.uwetech.dialog.hide();});
            //console.log(g.queuedActions[0]);
              npc_Alden.talking = false;
          } else if (npc_Alden.talking === false) {
            // test code to start alden talking again if the queue will be empty after this cycle.
              if (g.queuedActions.length <= 1) {
                  npc_Alden.talking = true; // make him talk on next spacebar press
              }
          }
      } else {
        if (npc_Alden.talking === undefined) {
            npc_Alden.talking = true;   // test code forces Alden to start talking.
        }
        if (npc_Alden.talking === true) {
          var dialogSize = interactNPC.dialog.length;
          for(var i = 0; i < dialogSize; i++) {

            var text = interactNPC.dialog[i];
            var face = interactNPC.faceArray[i];
            var faceSpot = interactNPC.faceSpot;

            if(faceSpot === 0 ){
              g.queuedActions.push((function (text, face) {
                     return function () {
                         window.uwetech.dialog.showRight(text, face);
                     };
                  })(text, face));
            }
            if(faceSpot === 1) {
              g.queuedActions.push((function (text, face) {
                     return function () {
                         window.uwetech.dialog.show(text, face);
                     };
                  })(text, face));
            }

            console.log(text);
          }
          interactNPC.talkTo ^= true;
          g.queuedActions.push(function () {window.uwetech.dialog.hide();});
          npc_Alden.talking = false;
        } else if (npc_Alden.talking === false) {
          // test code to start alden talking again if the queue will be empty after this cycle.
            if (g.queuedActions.length <= 1) {
                npc_Alden.talking = true; // make him talk on next spacebar press
            }
        }
      }
        /** This logic will check if any actions are currently queued and pause the game.
         * Then the action at the front of the queue is called. If the action just called
         * results in the queue now being empty, the game is also un-paused. */
        if (g.queuedActions.length > 0 && g.queuedActions !== undefined) {
            g.isPaused = true;
            g.timer.isPaused = true;
            g.queuedActions.shift()();

            if (g.queuedActions.length === 0) {
                g.isPaused = false;
                g.timer.isPaused = false;
            }
        }


    };

    /**
     * TODO: Add comments about what spriteRoll is.
     * @param srY
     * @param maxLength
     * @param tick
     * @param frameDuration
     */
    this.spriteRoll = function(srY, maxLength, tick, frameDuration) {
        this.elapsedTime += tick;
        this.frameDuration = frameDuration;
        this.totalTime = frameDuration*maxLength;

        if ((this.elapsedTime >= this.totalTime)) {
          this.elapsedTime = 0;
        }

        this.srcY = srY;
        this.imgX += 1;



        this.srcX = this.dtx * Math.floor(this.elapsedTime / this.frameDuration);

        if (this.imgX >= maxLength) {
            this.imgX = 0;
        }
    };

    this.currentFrame = function () {
        return Math.floor(this.elapsedTime / this.frameDuration);
    };

    this.update = function() {

    };
};


/**
 * Kirsten's added this code for Background Object. This is really just to
 * render the background of a zone. I just didn't want it as part of the
 * Sprite code because it is so simple and doesn't really "do" stuff.
 */
var BackgroundObject = function() {
    this.load = false;

    this.srcX = 0;
    this.srcY = 0;
    this.dtx = btmcanvas.width;
    this.dty = btmcanvas.height;
    this.x = 0;
    this.y = 0;
    this.width = btmcanvas.width;
    this.height = btmcanvas.height;

    /**
     * Sets the current background to the passed Image object.
     * @param image_object
     */
    this.set = function(image_object) {
        this.image = image_object;

        this.renderBackground = function(xoffset, yoffset) {
            btmctx.drawImage(this.image, this.srcX + xoffset, this.srcY + yoffset,
                this.dtx, this.dty,
                this.x, this.y, this.width, this.height);
        };

        this.debugOn = function (xoffset, yoffset) {
            //btmctx.clearRect(0, 0, topcanvas.width, topcanvas.height);
            btmctx.font = "bold 16px sans-serif";
            btmctx.fillStyle = "#ff00ee";

            for (var y = Math.floor(yoffset / 32); y < sign_screen_bounds.length; y += 1) {
                for (var x = Math.floor(xoffset / 32); x < sign_screen_bounds[0].length; x += 1) {
                    var value = sign_screen_bounds[y][x];
                    btmctx.fillText(value,x * 32 - xoffset + 10,
                        32 + y * 32 - yoffset - 10);
                }
            }
        };
    };
};

var player = new Sprite();
var npc_Chin = new Sprite();
var npc_Alden = new Sprite();

var npc_Map1StairWalker = new Sprite();
var npc_Map1BottomWalker = new Sprite();
var npc_Map1dummyOne = new Sprite();
var npc_Map1dummyTwo = new Sprite();
var npc_Map1dummyThree = new Sprite();
var npc_Map1Blocker = new Sprite();

var npc_Map2Cashier = new Sprite();
var npc_Map2Bookman = new Sprite();

var npc_Map3BottomWalker = new Sprite();
var npc_Map3dummyOne = new Sprite();
var npc_Map3dummyTwo = new Sprite();
var npc_Map3dummyThree = new Sprite();
var npc_Map3dummyFour = new Sprite();
var npc_Map3dummyFive = new Sprite();
var npc_Map3dummySix = new Sprite();
var npc_Map3Jay = new Sprite();
var npc_Map3SilentBob = new Sprite();

var npc_Map4theChin = new Sprite();
var npc_Map4frontStudentOne = new Sprite();
var npc_Map4frontStudentTwo = new Sprite();
var npc_Map4middleStudentOne = new Sprite();
var npc_Map4middleStudentTwo = new Sprite();
var npc_Map4backStudentOne = new Sprite();

var npc_Map5dummyOne = new Sprite();
var npc_Map5dummyTwo = new Sprite();

var npc_Map6lib = new Sprite();

var npc_Map7dummyOne = new Sprite();
var npc_Map7dummyTwo = new Sprite();
var npc_Map7dummyThree = new Sprite();
var npc_Map7dummyFour = new Sprite();

var npc_Map8dummyOne = new Sprite();
var npc_Map8dummyTwo = new Sprite();
var npc_Map8dummyThree = new Sprite();
var npc_Map8dummyFour = new Sprite();

var npc_Map10dummyOne = new Sprite();
var npc_Map10dummyTwo = new Sprite();
var npc_Map10dummyThree = new Sprite();
var npc_Map10dummyFour = new Sprite();
var npc_Map10theAlden = new Sprite();
//var background = new Sprite();

// var alden_por = new Dialog();


// src, srcX, srcY, dtx, dty, x, y, width, height, speed

// NPC's
player.setOptions("./img/purple_orc.png", 0, 640, 64, 64,
                                    0, 0, 64, 64, 3);
//npc_Mobus.setOptions("./img/mobus.png", 0, 640, 64, 64, 350, 10, 62, 62, 1);

npc_Map1StairWalker.setOptions("./img/NPC/guyOne.png", 0, 140, 64, 64, 350,10, 62, 62, 1);
npc_Map1BottomWalker.setOptions("./img/NPC/spriteRobert.png", 0, 140, 64, 64, 300, 1020, 62, 62, 2);
npc_Map1Blocker.setOptions("./img/NPC/girlOne.png", 0, 140, 64, 64, 530, 141, 62, 62, 2);
npc_Map1dummyOne.setOptions("./img/NPC/girlOne.png", 0, 140, 64, 64, 100, 500, 62, 62, 2);
npc_Map1dummyTwo.setOptions("./img/NPC/monk.png", 0, 140, 64, 64, 150, 900, 62, 62, 2);
npc_Map1dummyThree.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 150, 150, 62, 62, 2);


npc_Map2Cashier.setOptions("./img/NPC/guyTwo.png", 0, 140, 64, 64, -15,155, 62, 62, 0);
npc_Map2Bookman.setOptions("./img/NPC/girlTwo.png", 0, 140, 64, 64, 430, 40, 62, 62, 0);

npc_Map3BottomWalker.setOptions("./img/NPC/monk.png", 0, 140, 64, 64, 900, 600, 62, 62, 2);
npc_Map3dummyOne.setOptions("./img/NPC/girlOne.png", 0, 140, 64, 64, 800, 150, 62, 62, 2);
npc_Map3dummyTwo.setOptions("./img/NPC/girlTwo.png", 0, 140, 64, 64, 750, 175, 62, 62, 2);
npc_Map3dummyThree.setOptions("./img/NPC/girlThree.png", 0, 140, 64, 64, 770, 135, 62, 62, 2);
npc_Map3dummyFour.setOptions("./img/NPC/girlThree.png", 0, 140, 64, 64, 900, 400, 62, 62, 2);
npc_Map3dummyFive.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 400, 500, 62, 62, 2);
npc_Map3dummySix.setOptions("./img/NPC/monk.png", 0, 140, 64, 64, 400, -20, 62, 62, 2);
npc_Map3Jay.setOptions("./img/NPC/guyTwo.png", 0, 140, 64, 64, 90, 180, 62, 62, 2);
npc_Map3SilentBob.setOptions("./img/NPC/guyThree.png", 0, 140, 64, 64, 50, 180, 62, 62, 2);

npc_Map4theChin.setOptions("./img/NPC/chin.png", 0, 140, 64, 64, 515,20, 62, 62, 0);
npc_Map4frontStudentOne.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 440,20, 62, 62, 0);
npc_Map4frontStudentTwo.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 440,100, 62, 62, 0);
npc_Map4middleStudentOne.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 370,20, 62, 62, 0);
npc_Map4middleStudentTwo.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 370,100, 62, 62, 0);
npc_Map4backStudentOne.setOptions("./img/NPC/Skeleton.png", 0, 140, 64, 64, 250,100, 62, 62, 0);

npc_Map5dummyOne.setOptions("./img/NPC/chin.png", 0, 140, 64, 64, 110,260, 62, 62, 0);
npc_Map5dummyTwo.setOptions("./img/NPC/chin.png", 0, 140, 64, 64, 20,20, 62, 62, 0);

npc_Map6lib.setOptions("./img/NPC/chin.png", 0, 140, 64, 64, 150,145, 62, 62, 0);

npc_Map7dummyOne.setOptions("./img/NPC/girlOne.png", 0, 140, 64, 64, 50, 700, 62, 62, 2);
npc_Map7dummyTwo.setOptions("./img/NPC/girlTwo.png", 0, 140, 64, 64, 170, 200, 62, 62, 2);
npc_Map7dummyThree.setOptions("./img/NPC/girlThree.png", 0, 140, 64, 64, 350, 580, 62, 62, 2);
npc_Map7dummyFour.setOptions("./img/NPC/monk.png", 0, 140, 64, 64, 150, 200, 62, 62, 2);

npc_Map8dummyOne.setOptions("./img/NPC/girlOne.png", 0, 140, 64, 64, 50, 700, 62, 62, 2);
npc_Map8dummyTwo.setOptions("./img/NPC/girlTwo.png", 0, 140, 64, 64, 150, 0, 62, 62, 2);
npc_Map8dummyThree.setOptions("./img/NPC/girlThree.png", 0, 140, 64, 64, 350, 580, 62, 62, 2);
npc_Map8dummyFour.setOptions("./img/NPC/monk.png", 0, 140, 64, 64, 500, 900, 62, 62, 2);

npc_Map10dummyOne.setOptions("./img/NPC/girlOne.png", 0, 140, 64, 64, 210, 260, 62, 62, 2);
npc_Map10dummyTwo.setOptions("./img/NPC/girlTwo.png", 0, 140, 64, 64, 340, 260, 62, 62, 2);
npc_Map10dummyThree.setOptions("./img/NPC/girlThree.png", 0, 140, 64, 64, 210, 180, 62, 62, 2);
npc_Map10dummyFour.setOptions("./img/NPC/monk.png", 0, 140, 64, 64, 340, 180, 62, 62, 2);
npc_Map10theAlden.setOptions("./img/NPC/alden.png", 0, 140, 64, 64, 530, 170, 62, 62, 2);

npc_Map10theAlden.puzzleName = "Alden";

npc_Alden.face = (function () {
    var temp = new Image();
    temp.src =  "./img/Alden-plain.png";
    return temp;
})();
console.log(npc_Alden.face);

//Faces
// alden_por.setOptions("./img/Alden-plain.png", 0, 0, 480, 638, 100, 100, 480, 638);

var background = new BackgroundObject();
var initialBackground = new Image();
initialBackground.src = "./img/ext_stairs_lower.jpg";
background.set(initialBackground);

var grid = new BackgroundObject();
var gridimage = new Image();
gridimage.src = "./img/32x32grid.png";
grid.set(gridimage);

npc_Map1StairWalker.image.onload = function() {
  npc_Map1StairWalker.load = true;
  npc_Map1Blocker.load = true;
  npc_Map1BottomWalker.load = true;
  npc_Map1dummyOne.load = true;
  npc_Map1dummyTwo.load = true;
  npc_Map1dummyThree.load = true;

  npc_Map2Cashier.load = true;
  npc_Map2Bookman.load = true;

  npc_Map3BottomWalker.load = true;
  npc_Map3dummyOne.load = true;
  npc_Map3dummyTwo.load = true;
  npc_Map3dummyThree.load = true;
  npc_Map3dummyFour.load = true;
  npc_Map3dummyFive.load = true;
  npc_Map3dummySix.load = true;
  npc_Map3Jay.load = true;
  npc_Map3SilentBob.load = true;

  npc_Map4theChin.load = true;
  npc_Map4frontStudentOne.load = true;
  npc_Map4frontStudentTwo.load = true;
  npc_Map4middleStudentOne.load = true;
  npc_Map4middleStudentTwo.load = true;
  npc_Map4backStudentOne.load = true;

  npc_Map5dummyOne.load = true;
  npc_Map5dummyTwo.load = true;

  npc_Map6lib.load = true;

  npc_Map7dummyOne.load = true;
  npc_Map7dummyTwo.load = true;
  npc_Map7dummyThree.load = true;
  npc_Map7dummyFour.load = true;

  npc_Map8dummyOne.load = true;
  npc_Map8dummyTwo.load = true;
  npc_Map8dummyThree.load = true;
  npc_Map8dummyFour.load = true;

  npc_Map10dummyOne.load = true;
  npc_Map10dummyTwo.load = true;
  npc_Map10dummyThree.load = true;
  npc_Map10dummyFour.load = true;
  npc_Map10theAlden.load = true;

};

/*
Map1(bottomStaircase) Npc update functions are below
Blocker - If the player gets close he block you from going around.
Stairwalker - Walks up and down the stairs.. like a normal person.
BottomWalker - Walks left to right at the bottom of the stairs.. like a normal person.
*/
npc_Map1StairWalker.face.src = "./img/people/dude1.png";
npc_Map1StairWalker.faceArray[0] = npc_Map1StairWalker.face;
npc_Map1StairWalker.faceArray[1] = npc_Map1StairWalker.face;
npc_Map1StairWalker.dialog[0] = "I feel so animated! Running up! Running down!";
npc_Map1StairWalker.dialog[1] = "Up down, up down! Whoo, such an animated feeling!";

npc_Map1dummyTwo.face.src = "./img/Chin-plain.png";
npc_Map1dummyTwo.faceArray[0] = npc_Map1dummyTwo.face;
npc_Map1dummyTwo.faceArray[1] = npc_Map1dummyTwo.face;
npc_Map1dummyTwo.dialog[0] = "Can you direct me to WCG?  I'm looking for Dr. Chinn.  He's lost his marbles...or was it spilled his fruit."
npc_Map1dummyTwo.dialog[1] = "Anyway, he needs some help solving this mystery.  I heard he gives easy A's."

npc_Map1dummyOne.face.src = "./img/Alden-plain.png";
npc_Map1dummyOne.faceArray[0] = npc_Map1dummyOne.face;
npc_Map1dummyOne.faceArray[1] = npc_Map1dummyOne.face;
npc_Map1dummyOne.dialog[0] = "Do you know where the Science Building is?  <NAME> is up there exposing the inner workings of something called..."
npc_Map1dummyOne.dialog[1] = "computers, yeah that's it.  I heard there's a secret code to solving his puzzle."

npc_Map1dummyThree.face.src = "./img/Fowler-plain.png";
npc_Map1dummyThree.faceArray[0] = npc_Map1dummyThree.face;
npc_Map1dummyThree.faceArray[1] = npc_Map1dummyThree.face;
npc_Map1dummyThree.dialog[0] = "<NAME> is over in Cherry Parks.  He said my code is...how did he put it..."
npc_Map1dummyThree.dialog[1] = "'Your code is strange and unexpected. It is full of bugs.  Debug them if you can'"

npc_Map1BottomWalker.dialog[0] = "This stream of cars is never ending and the walk sign won't change! " +
                                 "I'll never be able to cross. I suggest you don't try either!";
npc_Map1BottomWalker.faceArray[0] = npc_Map1BottomWalker.face;
npc_Map1BottomWalker.face.src =  "./img/Robert.png";

npc_Map1Blocker.face.src = "./img/people/monika.png";
npc_Map1Blocker.faceArray[0] = npc_Map1Blocker.face;
npc_Map1Blocker.update = function(clockTick) {
  //console.log(this.talkTo);
  if(this.talkTo) {
    npc_Map1Blocker.dialog[0] = "Just go around me, why dontcha?";
  }
  if(!this.talkTo) {
    npc_Map1Blocker.dialog[0] = "Would you mind not blocking my path?";
  }
  if(player.y < 171) {
    if(W_KEY in keys || UP_KEY in keys) {
      this.spriteRoll(512, 8,  clockTick, 0.1);
      this.y = (player.y - 30);
    }
    if(S_KEY in keys || DOWN_KEY in keys) {
      this.spriteRoll(640, 8,  clockTick, 0.1);
      this.y = (player.y - 30);
    }
  }
};
npc_Map1dummyOne.update = function(clockTick) {
};
npc_Map1dummyTwo.update = function(clockTick) {
};
npc_Map1dummyThree.update = function(clockTick) {
};


var chinFlip = 0;
var chinCounter = 0;
var chinDirection = 0;

npc_Map1StairWalker.update = function(clockTick) {
  //console.log(player.y);
  //Checks to see if you are next to chin
  if(is_collide(this, player) && chinCounter === 0) {
    chinDirection = chinFlip;
    chinFlip = 3;
    chinCounter = 1;
  }

  //If you are next to chin then this happens.
  if(chinFlip === 3) {
    this.y += 0;
    if(chinDirection === 0) {
      this.spriteRoll(640, 1,  clockTick, 0.5);

    }
    if(chinDirection === 1) {
      this.spriteRoll(512, 1, clockTick, 0.5);
    }
    if(!is_collide(this, player)) {

      chinFlip = chinDirection;
    }
  }

  // You are not next to chin and he is walking south
  if(chinFlip === 0) {
    chinCounter = 0;
    this.spriteRoll(640, 8,  clockTick, 0.1);
    this.y += this.speed;

    if(this.y >= 700) {
      chinFlip = 1;
    }

  }

  // You are not next to chin and he is walking north
  if(chinFlip === 1) {
    chinCounter = 0;
    this.spriteRoll(512, 8, clockTick, 0.1);
    this.y -= this.speed;

    if(this.y <= 10) {
      chinFlip = 0;
    }
  }
};


var aldenFlip = 0;
var aldenCounter = 0;
var aldenDirection = 0;
npc_Map1BottomWalker.update = function(clockTick) {

  var aldenX = Math.floor(this.x/32) + 1;
  var aldenY = Math.floor(this.y/32) + 1

  //Checks to see if you are next to alden
  if(is_collide(this, player) && aldenCounter === 0) {
    aldenDirection = aldenFlip;
    aldenFlip = 3;
    aldenCounter = 1;
  }

  //If you are next to alden then this happens.
  if(aldenFlip === 3) {
    this.y += 0;
    if(aldenDirection === 0) {
      this.spriteRoll(704, 1,  clockTick, 0.5);

    }
    if(aldenDirection === 1) {
      this.spriteRoll(576, 1, clockTick, 0.5);

    }
    if(!is_collide(this, player)) {

      aldenFlip = aldenDirection;
    }
  }

  // You are not next to alden and he is walking west
  if(aldenFlip === 0) {
    aldenCounter = 0;
    this.spriteRoll(704, 8,  clockTick, 0.1);
    this.x += this.speed;

    if(this.x >= 450) {
      aldenFlip = 1;
    }

  }
  // You are not next to alden and he is walking east
  if(aldenFlip === 1) {
    aldenCounter = 0;
    this.spriteRoll(576, 8,  clockTick, 0.1);
    this.x -= this.speed;

    if(this.x <= 10) {
      aldenFlip = 0;
    }
  }
};

/*
Map2(BookStore) Npc update functions are below
Bookman - If the player gets close he looks for a book.
Cashier - If the player gets close he will check you out. *wink*
*/
npc_Map2Bookman.dialog[0] = "<NAME> taught me that a monkey can peel a Banana in O(log n) time.  That's pretty fast."
npc_Map2Bookman.update = function(clockTick) {
  //console.log(dist);
  if(is_collide(this, player)) {
    this.spriteRoll(780, 5,  clockTick, 0.3);
  } else {
    this.spriteRoll(780, 1,  clockTick, 0.3);
  }

};
npc_Map2Cashier.update = function(clockTick) {
  //console.log(dist);
  if(is_collide(this, player)) {
    this.spriteRoll(460, 8,  clockTick, 0.3);
  } else {
    this.spriteRoll(460, 1,  clockTick, 0.3);
  }

};

/*
Map3(walkWay) Npc update functions are below
dummyGroup - Just a bunch of friends talking and blocking the way.
dummyOne - the one on the far right
dummyTwo - the one furthest south
dummyThree - the one furthest north
bottomWalker - Walks left to right at the bottom of the stairs.. like a normal person.
*/

npc_Map3dummyOne.dialog[0] = "...and then I said...";
npc_Map3dummyOne.dialog[1] = "Would you mind? We are having a conversation about some cute boys.";
npc_Map3dummyOne.update = function(clockTick) {
  this.spriteRoll(576, 1,  clockTick, 0.1);
};
npc_Map3dummyTwo.dialog[0] = "Did he really say that?";
npc_Map3dummyTwo.update = function(clockTick) {
  this.spriteRoll(512, 1,  clockTick, 0.1);
};
npc_Map3dummyThree.dialog[0] = "He sounds so dreamy.";
npc_Map3dummyThree.update = function(clockTick) {
  this.spriteRoll(900, 1,  clockTick, 0.1);
};
npc_Map3dummyFour.face.src = "./img/people/Kirsten.png";
npc_Map3dummyFour.faceArray[0] = npc_Map3dummyFour.face;
npc_Map3dummyFour.faceArray[1] = npc_Map3dummyFour.face;
npc_Map3dummyFour.dialog[0] = "la, la, la, 867-5309. What was the rest of the song!?";
npc_Map3dummyFour.dialog[1] = "That number would make an awesome secret code though.";
npc_Map3dummyFour.update = function(clockTick) {
  this.spriteRoll(900, 1,  clockTick, 0.1);
};

npc_Map3dummyFive.face.src = "./img/people/dude2.png";
npc_Map3dummyFive.faceArray[0] = npc_Map3dummyFive.face;
npc_Map3dummyFive.faceArray[1] = npc_Map3dummyFive.face;
npc_Map3dummyFive.update = function(clockTick) {
  if(this.talkTo) {
    this.spriteRoll(704, 8,  clockTick, 0.1);
    this.x += this.speed;
  }
  if(!this.talkTo) {
    this.spriteRoll(900, 1,  clockTick, 0.1);
    npc_Map3dummyFive.dialog[0] = "Wait, when does this happen? Now?"
    npc_Map3dummyFive.dialog[1] = "You mean what I’m doing now is actually happening right now?"
  }
};
npc_Map3dummySix.face.src = "./img/people/Daniel.png";
npc_Map3dummySix.faceArray[0] = npc_Map3dummySix.face;
npc_Map3dummySix.faceArray[1] = npc_Map3dummySix.face;
npc_Map3dummySix.dialog[0] = "Have you seen that girl known as Jenny?"
npc_Map3dummySix.dialog[1] = "I hear her song is really catchy."
npc_Map3dummySix.update = function(clockTick) {
  this.spriteRoll(900, 1,  clockTick, 0.1);
};

// Kirsten and Loren veto'd cussing. We found a different jay/silent bob quote.
npc_Map3Jay.face.src =  "./img/people/Joel.png";
npc_Map3Jay.dialog[0] = "See those two over there? Yeah, they had a Star Wars themed wedding. ";
npc_Map3Jay.dialog[1] = ".......";
npc_Map3Jay.dialog[2] = "AND they tied the knot dressed as Storm Troopers!";
npc_Map3Jay.faceArray[0] = npc_Map3Jay.face;
npc_Map3Jay.faceArray[1] = npc_Map3SilentBob.face;
npc_Map3Jay.faceArray[2] = npc_Map3Jay.face;

npc_Map3SilentBob.faceSpot = 1;
npc_Map3SilentBob.face.src =  "./img/people/Aaron.png";
npc_Map3SilentBob.dialog[0] = "See those two over there? Yeah, they had a Star Wars themed wedding. ";
npc_Map3SilentBob.dialog[1] = ".......";
npc_Map3SilentBob.dialog[2] = "AND they tied the knot dressed as Storm Troopers!";
npc_Map3SilentBob.faceArray[0] = npc_Map3Jay.face;
npc_Map3SilentBob.faceArray[1] = npc_Map3SilentBob.face;
npc_Map3SilentBob.faceArray[2] = npc_Map3Jay.face;


npc_Map3Jay.update = function(clockTick) {
  this.spriteRoll(900, 1,  clockTick, 0.1);
};


npc_Map3SilentBob.update = function(clockTick) {
  this.spriteRoll(900, 1,  clockTick, 0.1);
}
npc_Map3BottomWalker.face.src =  "./img/people/Aaron.png";
npc_Map3BottomWalker.faceArray[0] = npc_Map3BottomWalker.face;
npc_Map3BottomWalker.dialog[0] = "Sunnyside is a place of ruin and despair, ruled by an evil bear who smells of strawberries!"
npc_Map3BottomWalker.update = function(clockTick) {
{'fraction_non_alphanumeric': 0.12959184876823474, 'fraction_numerical': 0.036652240055662345, 'mean_word_length': 2.350904923733502, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1238932', 'n_tokens_mistral': 31315, 'n_tokens_neox': 28053, 'n_words': 7710}