From f6cb01cc4d91a9deac8e8bb8d5bd4bbe6020304f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 8 Jan 2020 17:21:59 -0500 Subject: [PATCH 001/577] Set theme jekyll-theme-merlot --- _config.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 _config.yml diff --git a/_config.yml b/_config.yml new file mode 100644 index 00000000..c50ff38d --- /dev/null +++ b/_config.yml @@ -0,0 +1 @@ +theme: jekyll-theme-merlot \ No newline at end of file From b16ca060a743f4cc4808816a6357031bc2b303cd Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 8 Jan 2020 17:23:36 -0500 Subject: [PATCH 002/577] Create CNAME --- CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 CNAME diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..0c36ad75 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +poop.com \ No newline at end of file From 9a0d3726df16f35e23bf25f8b66af3e3cd359510 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 8 Jan 2020 17:23:48 -0500 Subject: [PATCH 003/577] Delete CNAME --- CNAME | 1 - 1 file changed, 1 deletion(-) delete mode 100644 CNAME diff --git a/CNAME b/CNAME deleted file mode 100644 index 0c36ad75..00000000 --- a/CNAME +++ /dev/null @@ -1 +0,0 @@ -poop.com \ No newline at end of file From b7939f697291f006fa34660d3260b93f20b5e194 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 12 Jan 2020 11:30:54 -0500 Subject: [PATCH 004/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index bdcf7822..4cb24fad 100644 --- a/a.js +++ b/a.js @@ -2221,7 +2221,7 @@ function render() { if (countSnakes() === 0) { context.fillStyle = "#ff0"; context.font = "100px Arial"; - context.fillText("You Win!", 0, canvas.height / 2); + context.fillText("test!", 0, canvas.height / 2); } if (isDead()) { context.fillStyle = "#f00"; From 5fa63e57fcca14c632f173f0bf78cffaa861f64b Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 15:55:49 -0500 Subject: [PATCH 005/577] Create index --- index | 82 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 index diff --git a/index b/index new file mode 100644 index 00000000..7ea92665 --- /dev/null +++ b/index @@ -0,0 +1,82 @@ + + + Snakefall + + + + + + + + + +
+ +
+
+ Controls (hover for hotkeys): +
+ Arrows/WASD to move + + +
+ + Moves: 0+0 + + + +
+ + + + +
This project on Github: thejoshwolfe/snakefall version ???
+
Check out some community made levels, and share your levels there!
+
Also check out the experimental versions of this game.
+
This game is a clone of Snakebird by Noumenon Games.
+ + + + + From 13adf1526e0eb1211541d927a510583983c369a7 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 15:57:00 -0500 Subject: [PATCH 006/577] Delete index.html --- index.html | 77 ------------------------------------------------------ 1 file changed, 77 deletions(-) delete mode 100644 index.html diff --git a/index.html b/index.html deleted file mode 100644 index 358a21d9..00000000 --- a/index.html +++ /dev/null @@ -1,77 +0,0 @@ - - - Snakefall - - - - - - -
- -
-
- Controls (hover for hotkeys): -
- Arrows/WASD to move - - -
- - Moves: 0+0 - - - -
- - - - -
This project on Github: thejoshwolfe/snakefall version ???
-
Check out some community made levels, and share your levels there!
-
Also check out the experimental versions of this game.
-
This game is a clone of Snakebird by Noumenon Games.
- - - - From da65c8a3295368f3d86ffcb906dc11f5e96036d0 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 15:57:14 -0500 Subject: [PATCH 007/577] Rename index to index.html --- index => index.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename index => index.html (100%) diff --git a/index b/index.html similarity index 100% rename from index rename to index.html From 871ca1397594dd7b6b9e9ccfbcf88b8b4d54c41d Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 15:57:35 -0500 Subject: [PATCH 008/577] Delete a.js --- a.js | 2758 ---------------------------------------------------------- 1 file changed, 2758 deletions(-) delete mode 100644 a.js diff --git a/a.js b/a.js deleted file mode 100644 index 4cb24fad..00000000 --- a/a.js +++ /dev/null @@ -1,2758 +0,0 @@ -function unreachable() { return new Error("unreachable"); } -if (typeof VERSION !== "undefined") { - document.getElementById("versionSpan").innerHTML = - '' + VERSION.tag + ''; -} -var canvas = document.getElementById("canvas"); - -// tile codes -var SPACE = 0; -var WALL = 1; -var SPIKE = 2; -var FRUIT_v0 = 3; // legacy -var EXIT = 4; -var PORTAL = 5; -var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL]; - -// object types -var SNAKE = "s"; -var BLOCK = "b"; -var FRUIT = "f"; - -var tileSize = 30; -var level; -var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; -var uneditStuff = {undoStack:[], redoStack:[], spanId:"editsSpan", undoButtonId:"uneditButton", redoButtonId:"reeditButton"}; -var paradoxes = []; -function loadLevel(newLevel) { - level = newLevel; - currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); - - activateAnySnakePlease(); - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - undoStuffChanged(unmoveStuff); - uneditStuff.undoStack = []; - uneditStuff.redoStack = []; - undoStuffChanged(uneditStuff); - blockSupportRenderCache = {}; - render(); -} - - -var magicNumber_v0 = "3tFRIoTU"; -var magicNumber = "HyRr4JK1"; -var exampleLevel = magicNumber_v0 + "&" + - "17&31" + - "?" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000040000000000" + - "0000000000000110000000000000000" + - "0000000000000111100000000000000" + - "0000000000000011000000000000000" + - "0000000000000010000010000000000" + - "0000000000000010100011000000000" + - "0000001111111000110000000110000" + - "0000011111111111111111111110000" + - "0000011111111101111111111100000" + - "0000001111111100111111111100000" + - "0000001111111000111111111100000" + - "/" + - "s0 ?351&350&349/" + - "f0 ?328/" + - "f1 ?366/"; - -var testLevel_v0 = "3tFRIoTU&5&5?0005*00300024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/"; -var testLevel_v0_converted = "HyRr4JK1&5&5?0005*4024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/f0?8/"; - -function parseLevel(string) { - // magic number - var cursor = 0; - skipWhitespace(); - var versionTag = string.substr(cursor, magicNumber.length); - switch (versionTag) { - case magicNumber_v0: - case magicNumber: break; - default: throw new Error("not a snakefall level"); - } - cursor += magicNumber.length; - consumeKeyword("&"); - - var level = { - height: -1, - width: -1, - map: [], - objects: [], - }; - - // height, width - level.height = readInt(); - consumeKeyword("&"); - level.width = readInt(); - - // map - var mapData = readRun(); - mapData = decompressSerialization(mapData); - if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); - var upconvertedObjects = []; - var fruitCount = 0; - for (var i = 0; i < mapData.length; i++) { - var tileCode = mapData[i].charCodeAt(0) - "0".charCodeAt(0); - if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { - // fruit used to be a tile code. now it's an object. - upconvertedObjects.push({ - type: FRUIT, - id: fruitCount++, - dead: false, // unused - locations: [i], - }); - tileCode = SPACE; - } - if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); - level.map.push(tileCode); - } - - // objects - skipWhitespace(); - while (cursor < string.length) { - var object = { - type: "?", - id: -1, - dead: false, - locations: [], - }; - - // type - object.type = string[cursor]; - var locationsLimit; - if (object.type === SNAKE) locationsLimit = -1; - else if (object.type === BLOCK) locationsLimit = -1; - else if (object.type === FRUIT) locationsLimit = 1; - else throw parserError("expected object type code"); - cursor += 1; - - // id - object.id = readInt(); - - // locations - var locationsData = readRun(); - var locationStrings = locationsData.split("&"); - if (locationStrings.length === 0) throw parserError("locations must be non-empty"); - if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); - - locationStrings.forEach(function(locationString) { - var location = parseInt(locationString); - if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); - object.locations.push(location); - }); - - level.objects.push(object); - skipWhitespace(); - } - for (var i = 0; i < upconvertedObjects.length; i++) { - level.objects.push(upconvertedObjects[i]); - } - - return level; - - function skipWhitespace() { - while (" \n\t\r".indexOf(string[cursor]) !== -1) { - cursor += 1; - } - } - function consumeKeyword(keyword) { - skipWhitespace(); - if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); - cursor += 1; - } - function readInt() { - skipWhitespace(); - for (var i = cursor; i < string.length; i++) { - if ("0123456789".indexOf(string[i]) === -1) break; - } - var substring = string.substring(cursor, i); - if (substring.length === 0) throw parserError("expected int"); - cursor = i; - return parseInt(substring, 10); - } - function readRun() { - consumeKeyword("?"); - var endIndex = string.indexOf("/", cursor); - var substring = string.substring(cursor, endIndex); - cursor = endIndex + 1; - return substring; - } - function parserError(message) { - return new Error("parse error at position " + cursor + ": " + message); - } -} - -function stringifyLevel(level) { - var output = magicNumber + "&"; - output += level.height + "&" + level.width + "\n"; - - output += "?\n"; - for (var r = 0; r < level.height; r++) { - output += " " + level.map.slice(r * level.width, (r + 1) * level.width).join("") + "\n"; - } - output += "/\n"; - - output += serializeObjects(level.objects); - - // sanity check - var shouldBeTheSame = parseLevel(output); - if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken - - return output; -} -function serializeObjects(objects) { - var output = ""; - for (var i = 0; i < objects.length; i++) { - var object = objects[i]; - output += object.type + object.id + " "; - output += "?" + object.locations.join("&") + "/\n"; - } - return output; -} -function serializeObjectState(object) { - if (object == null) return [0,[]]; - return [object.dead, copyArray(object.locations)]; -} - -var base66 = "----0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -function compressSerialization(string) { - string = string.replace(/\s+/g, ""); - // run-length encode several 0's in a row, etc. - // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) - var result = ""; - var runStart = 0; - for (var i = 1; i < string.length + 1; i++) { - var runLength = i - runStart; - if (string[i] === string[runStart] && runLength < base66.length - 1) continue; - // end of run - if (runLength >= 4) { - // compress - result += "*" + base66[runLength] + string[runStart]; - } else { - // literal - result += string.substring(runStart, i); - } - runStart = i; - } - return result; -} -function decompressSerialization(string) { - string = string.replace(/\s+/g, ""); - var result = ""; - for (var i = 0; i < string.length; i++) { - if (string[i] === "*") { - i += 1; - var runLength = base66.indexOf(string[i]); - i += 1; - var char = string[i]; - for (var j = 0; j < runLength; j++) { - result += char; - } - } else { - result += string[i]; - } - } - return result; -} - -var replayMagicNumber = "nmGTi8PB"; -function stringifyReplay() { - var output = replayMagicNumber + "&"; - // only specify the snake id in an input if it's different from the previous. - // the first snake index is 0 to optimize for the single-snake case. - var currentSnakeId = 0; - for (var i = 0; i < unmoveStuff.undoStack.length; i++) { - var firstChange = unmoveStuff.undoStack[i][0]; - if (firstChange[0] !== "i") throw unreachable(); - var snakeId = firstChange[1]; - var dr = firstChange[2]; - var dc = firstChange[3]; - var directionCode; - if (dr ===-1 && dc === 0) directionCode = "u"; - else if (dr === 0 && dc ===-1) directionCode = "l"; - else if (dr === 1 && dc === 0) directionCode = "d"; - else if (dr === 0 && dc === 1) directionCode = "r"; - else throw unreachable(); - if (snakeId !== currentSnakeId) { - output += snakeId; // int to string - currentSnakeId = snakeId; - } - output += directionCode; - } - return output; -} -function parseAndLoadReplay(string) { - string = decompressSerialization(string); - var expectedPrefix = replayMagicNumber + "&"; - if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); - var cursor = expectedPrefix.length; - - // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. - activeSnakeId = 0; - while (cursor < string.length) { - var snakeIdStr = ""; - var c = string.charAt(cursor); - cursor += 1; - while ('0' <= c && c <= '9') { - snakeIdStr += c; - if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); - c = string.charAt(cursor); - cursor += 1; - } - if (snakeIdStr.length > 0) { - activeSnakeId = parseInt(snakeIdStr); - // don't just validate when switching snakes, but on every move. - } - - // doing a move. - if (!getSnakes().some(function(snake) { - return snake.id === activeSnakeId; - })) { - throw new Error("invalid snake id: " + activeSnakeId); - } - switch (c) { - case 'l': move( 0, -1); break; - case 'u': move(-1, 0); break; - case 'r': move( 0, 1); break; - case 'd': move( 1, 0); break; - default: throw new Error("replay string has invalid direction: " + c); - } - } - - // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. - reset(unmoveStuff); - document.getElementById("removeButton").classList.add("click-me"); -} - -var currentSerializedLevel; -function saveLevel() { - if (isDead()) return alert("Can't save while you're dead!"); - var serializedLevel = compressSerialization(stringifyLevel(level)); - currentSerializedLevel = serializedLevel; - var hash = "#level=" + serializedLevel; - expectHash = hash; - location.hash = hash; - - // This marks a starting point for solving the level. - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - editorHasBeenTouched = false; - undoStuffChanged(unmoveStuff); -} - -function saveReplay() { - if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); - // preserve the level in the url bar. - var hash = "#level=" + currentSerializedLevel; - if (dirtyState === REPLAY_DIRTY) { - // there is a replay to save - hash += "#replay=" + compressSerialization(stringifyReplay()); - } - expectHash = hash; - location.hash = hash; -} - -function deepEquals(a, b) { - if (a == null) return b == null; - if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; - if (Array.isArray(a)) { - if (!Array.isArray(b)) return false; - if (a.length !== b.length) return false; - for (var i = 0; i < a.length; i++) { - if (!deepEquals(a[i], b[i])) return false; - } - return true; - } - // must be objects - var aKeys = Object.keys(a); - var bKeys = Object.keys(b); - if (aKeys.length !== bKeys.length) return false; - aKeys.sort(); - bKeys.sort(); - if (!deepEquals(aKeys, bKeys)) return false; - for (var i = 0; i < aKeys.length; i++) { - if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; - } - return true; -} - -function getLocation(level, r, c) { - if (!isInBounds(level, r, c)) throw unreachable(); - return r * level.width + c; -} -function getRowcol(level, location) { - if (location < 0 || location >= level.width * level.height) throw unreachable(); - var r = Math.floor(location / level.width); - var c = location % level.width; - return {r:r, c:c}; -} -function isInBounds(level, r, c) { - if (c < 0 || c >= level.width) return false;; - if (r < 0 || r >= level.height) return false;; - return true; -} -function offsetLocation(location, dr, dc) { - var rowcol = getRowcol(level, location); - return getLocation(level, rowcol.r + dr, rowcol.c + dc); -} - -var SHIFT = 1; -var CTRL = 2; -var ALT = 4; -document.addEventListener("keydown", function(event) { - var modifierMask = ( - (event.shiftKey ? SHIFT : 0) | - (event.ctrlKey ? CTRL : 0) | - (event.altKey ? ALT : 0) - ); - switch (event.keyCode) { - case 37: // left - if (modifierMask === 0) { move(0, -1); break; } - return; - case 38: // up - if (modifierMask === 0) { move(-1, 0); break; } - return; - case 39: // right - if (modifierMask === 0) { move(0, 1); break; } - return; - case 40: // down - if (modifierMask === 0) { move(1, 0); break; } - return; - case 8: // backspace - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Q".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Z".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { undo(uneditStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL|SHIFT) { redo(uneditStuff); break; } - return; - case "Y".charCodeAt(0): - if (modifierMask === 0) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { redo(uneditStuff); break; } - return; - case "R".charCodeAt(0): - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } - if (modifierMask === 0) { reset(unmoveStuff); break; } - if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } - return; - - case 220: // backslash - if (modifierMask === 0) { toggleShowEditor(); break; } - return; - case "A".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, -1); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PORTAL); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { selectAll(); break; } - return; - case "E".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - return; - case 46: // delete - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - return; - case "W".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } - return; - case "S".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPIKE); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { saveLevel(); break; } - if (!persistentState.showEditor && modifierMask === CTRL) { saveReplay(); break; } - if (modifierMask === (CTRL|SHIFT)) { saveReplay(); break; } - return; - case "X".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(EXIT); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } - return; - case "F".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } - return; - case "D".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SNAKE); break; } - return; - case "B".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } - return; - case "G".charCodeAt(0): - if (modifierMask === 0) { toggleGrid(); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } - return; - case "C".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === SHIFT) { toggleCollision(); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } - return; - case "V".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } - return; - case 32: // spacebar - case 9: // tab - if (modifierMask === 0) { switchSnakes( 1); break; } - if (modifierMask === SHIFT) { switchSnakes(-1); break; } - return; - case "1".charCodeAt(0): - case "2".charCodeAt(0): - case "3".charCodeAt(0): - case "4".charCodeAt(0): - var index = event.keyCode - "1".charCodeAt(0); - var delta; - if (modifierMask === 0) { - delta = 1; - } else if (modifierMask === SHIFT) { - delta = -1; - } else return; - if (isAlive()) { - (function() { - var snakes = findSnakesOfColor(index); - if (snakes.length === 0) return; - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; - } - } - activeSnakeId = snakes[0].id; - })(); - } - break; - case 27: // escape - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(null); break; } - return; - default: return; - } - event.preventDefault(); - render(); -}); - -document.getElementById("switchSnakesButton").addEventListener("click", function() { - switchSnakes(1); - render(); -}); -function switchSnakes(delta) { - if (!isAlive()) return; - var snakes = getSnakes(); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; - } - } - activeSnakeId = snakes[0].id; -} -document.getElementById("showGridButton").addEventListener("click", function() { - toggleGrid(); -}); -document.getElementById("saveProgressButton").addEventListener("click", function() { - saveReplay(); -}); -document.getElementById("restartButton").addEventListener("click", function() { - reset(unmoveStuff); - render(); -}); -document.getElementById("unmoveButton").addEventListener("click", function() { - undo(unmoveStuff); - render(); -}); -document.getElementById("removeButton").addEventListener("click", function() { - redo(unmoveStuff); - render(); -}); - -document.getElementById("showHideEditor").addEventListener("click", function() { - toggleShowEditor(); -}); -function toggleShowEditor() { - persistentState.showEditor = !persistentState.showEditor; - savePersistentState(); - showEditorChanged(); -} -function toggleGrid() { - persistentState.showGrid = !persistentState.showGrid; - savePersistentState(); - render(); -} -["serializationTextarea", "shareLinkTextbox"].forEach(function(id) { - document.getElementById(id).addEventListener("keydown", function(event) { - // let things work normally - event.stopPropagation(); - }); -}); -document.getElementById("submitSerializationButton").addEventListener("click", function() { - var string = document.getElementById("serializationTextarea").value; - try { - var newLevel = parseLevel(string); - } catch (e) { - alert(e); - return; - } - loadLevel(newLevel); -}); -document.getElementById("shareLinkTextbox").addEventListener("focus", function() { - setTimeout(function() { - document.getElementById("shareLinkTextbox").select(); - }, 0); -}); - -var paintBrushTileCode = null; -var paintBrushSnakeColorIndex = 0; -var paintBrushBlockId = 0; -var paintBrushObject = null; -var selectionStart = null; -var selectionEnd = null; -var resizeDragAnchorRowcol = null; -var clipboardData = null; -var clipboardOffsetRowcol = null; -var paintButtonIdAndTileCodes = [ - ["resizeButton", "resize"], - ["selectButton", "select"], - ["pasteButton", "paste"], - ["paintSpaceButton", SPACE], - ["paintWallButton", WALL], - ["paintSpikeButton", SPIKE], - ["paintExitButton", EXIT], - ["paintFruitButton", FRUIT], - ["paintPortalButton", PORTAL], - ["paintSnakeButton", SNAKE], - ["paintBlockButton", BLOCK], -]; -paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - document.getElementById(id).addEventListener("click", function() { - setPaintBrushTileCode(tileCode); - }); -}); -document.getElementById("uneditButton").addEventListener("click", function() { - undo(uneditStuff); - render(); -}); -document.getElementById("reeditButton").addEventListener("click", function() { - redo(uneditStuff); - render(); -}); -document.getElementById("saveLevelButton").addEventListener("click", function() { - saveLevel(); -}); -document.getElementById("copyButton").addEventListener("click", function() { - copySelection(); -}); -document.getElementById("cutButton").addEventListener("click", function() { - cutSelection(); -}); -document.getElementById("cheatGravityButton").addEventListener("click", function() { - toggleGravity(); -}); -document.getElementById("cheatCollisionButton").addEventListener("click", function() { - toggleCollision(); -}); -function toggleGravity() { - isGravityEnabled = !isGravityEnabled; - isCollisionEnabled = true; - refreshCheatButtonText(); -} -function toggleCollision() { - isCollisionEnabled = !isCollisionEnabled; - isGravityEnabled = false; - refreshCheatButtonText(); -} -function refreshCheatButtonText() { - document.getElementById("cheatGravityButton").textContent = isGravityEnabled ? "Gravity: ON" : "Gravity: OFF"; - document.getElementById("cheatGravityButton").style.background = isGravityEnabled ? "" : "#f88"; - - document.getElementById("cheatCollisionButton").textContent = isCollisionEnabled ? "Collision: ON" : "Collision: OFF"; - document.getElementById("cheatCollisionButton").style.background = isCollisionEnabled ? "" : "#f88"; -} - -// be careful with location vs rowcol, because this variable is used when resizing -var lastDraggingRowcol = null; -var hoverLocation = null; -var draggingChangeLog = null; -canvas.addEventListener("mousedown", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - var location = getLocationFromEvent(event); - if (persistentState.showEditor && paintBrushTileCode != null) { - // editor tool - lastDraggingRowcol = getRowcol(level, location); - if (paintBrushTileCode === "select") selectionStart = location; - if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; - draggingChangeLog = []; - paintAtLocation(location, draggingChangeLog); - } else { - // playtime - var object = findObjectAtLocation(location); - if (object == null) return; - if (object.type !== SNAKE) return; - // active snake - activeSnakeId = object.id; - render(); - } -}); -canvas.addEventListener("dblclick", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - if (persistentState.showEditor && paintBrushTileCode === "select") { - // double click with select tool - var location = getLocationFromEvent(event); - var object = findObjectAtLocation(location); - if (object == null) return; - stopDragging(); - if (object.type === SNAKE) { - // edit snakes of this color - paintBrushTileCode = SNAKE; - paintBrushSnakeColorIndex = object.id % snakeColors.length; - } else if (object.type === BLOCK) { - // edit this particular block - paintBrushTileCode = BLOCK; - paintBrushBlockId = object.id; - } else if (object.type === FRUIT) { - // edit fruits, i guess - paintBrushTileCode = FRUIT; - } else throw unreachable(); - paintBrushTileCodeChanged(); - } -}); -document.addEventListener("mouseup", function(event) { - stopDragging(); -}); -function stopDragging() { - if (lastDraggingRowcol != null) { - // release the draggin' - lastDraggingRowcol = null; - paintBrushObject = null; - resizeDragAnchorRowcol = null; - pushUndo(uneditStuff, draggingChangeLog); - draggingChangeLog = null; - } -} -canvas.addEventListener("mousemove", function(event) { - if (!persistentState.showEditor) return; - var location = getLocationFromEvent(event); - var mouseRowcol = getRowcol(level, location); - if (lastDraggingRowcol != null) { - // Dragging Force - Through the Fruit and Flames - var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); - // we need to get rowcols for everything before we start dragging, because dragging might resize the world. - var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function(location) { - return getRowcol(level, location); - }); - path.forEach(function(rowcol) { - // convert to location at the last minute in case each of these steps is changing the coordinate system. - paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); - }); - lastDraggingRowcol = mouseRowcol; - hoverLocation = null; - } else { - // hovering - if (hoverLocation !== location) { - hoverLocation = location; - render(); - } - } -}); -canvas.addEventListener("mouseout", function() { - if (hoverLocation !== location) { - // turn off the hover when the mouse leaves - hoverLocation = null; - render(); - } -}); -function getLocationFromEvent(event) { - var r = Math.floor(eventToMouseY(event, canvas) / tileSize); - var c = Math.floor(eventToMouseX(event, canvas) / tileSize); - // since the canvas is centered, the bounding client rect can be half-pixel aligned, - // resulting in slightly out-of-bounds mouse events. - r = clamp(r, 0, level.height); - c = clamp(c, 0, level.width); - return getLocation(level, r, c); -} -function eventToMouseX(event, canvas) { return event.clientX - canvas.getBoundingClientRect().left; } -function eventToMouseY(event, canvas) { return event.clientY - canvas.getBoundingClientRect().top; } - -function selectAll() { - selectionStart = 0; - selectionEnd = level.map.length - 1; - setPaintBrushTileCode("select"); -} - -function setPaintBrushTileCode(tileCode) { - if (tileCode === "paste") { - // make sure we have something to paste - if (clipboardData == null) return; - } - if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { - // usually this means to fill in the selection - if (tileCode == null) { - // cancel selection - selectionStart = null; - selectionEnd = null; - return; - } - if (typeof tileCode === "number" && tileCode !== PORTAL) { - // fill in the selection - fillSelection(tileCode); - selectionStart = null; - selectionEnd = null; - return; - } - // ok, just select something else then. - selectionStart = null; - selectionEnd = null; - } - if (tileCode === SNAKE) { - if (paintBrushTileCode === SNAKE) { - // next snake color - paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; - } - } else if (tileCode === BLOCK) { - var blocks = getBlocks(); - if (paintBrushTileCode === BLOCK && blocks.length > 0) { - // cycle through block ids - blocks.sort(compareId); - if (paintBrushBlockId != null) { - (function() { - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id === paintBrushBlockId) { - i += 1; - if (i < blocks.length) { - // next block id - paintBrushBlockId = blocks[i].id; - } else { - // new block id - paintBrushBlockId = null; - } - return; - } - } - throw unreachable() - })(); - } else { - // first one - paintBrushBlockId = blocks[0].id; - } - } else { - // new block id - paintBrushBlockId = null; - } - } else if (tileCode == null) { - // escape - if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { - // stop editing this block, but keep the block brush selected - tileCode = BLOCK; - paintBrushBlockId = null; - } - } - paintBrushTileCode = tileCode; - paintBrushTileCodeChanged(); -} -function paintBrushTileCodeChanged() { - paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - var backgroundStyle = ""; - if (tileCode === paintBrushTileCode) { - if (tileCode === SNAKE) { - // show the color of the active snake in the color of the button - backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; - } else { - backgroundStyle = "#ff0"; - } - } - document.getElementById(id).style.background = backgroundStyle; - }); - - var isSelectionMode = paintBrushTileCode === "select"; - ["cutButton", "copyButton"].forEach(function (id) { - document.getElementById(id).disabled = !isSelectionMode; - }); - document.getElementById("pasteButton").disabled = clipboardData == null; - - render(); -} - -function cutSelection() { - copySelection(); - fillSelection(SPACE); - render(); -} -function copySelection() { - var selectedLocations = getSelectedLocations(); - if (selectedLocations.length === 0) return; - var selectedObjects = []; - selectedLocations.forEach(function(location) { - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(selectedObjects, object); - }); - setClipboardData({ - level: JSON.parse(JSON.stringify(level)), - selectedLocations: selectedLocations, - selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), - }); -} -function setClipboardData(data) { - // find the center - var minR = Infinity; - var maxR = -Infinity; - var minC = Infinity; - var maxC = -Infinity; - data.selectedLocations.forEach(function(location) { - var rowcol = getRowcol(data.level, location); - if (rowcol.r < minR) minR = rowcol.r; - if (rowcol.r > maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var offsetR = Math.floor((minR + maxR) / 2); - var offsetC = Math.floor((minC + maxC) / 2); - - clipboardData = data; - clipboardOffsetRowcol = {r:offsetR, c:offsetC}; - paintBrushTileCodeChanged(); -} -function fillSelection(tileCode) { - var changeLog = []; - var locations = getSelectedLocations(); - locations.forEach(function(location) { - if (level.map[location] !== tileCode) { - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; - } - removeAnyObjectAtLocation(location, changeLog); - }); - pushUndo(uneditStuff, changeLog); -} -function getSelectedLocations() { - if (selectionStart == null || selectionEnd == null) return []; - var rowcol1 = getRowcol(level, selectionStart); - var rowcol2 = getRowcol(level, selectionEnd); - var r1 = rowcol1.r; - var c1 = rowcol1.c; - var r2 = rowcol2.r; - var c2 = rowcol2.c; - if (r2 < r1) { - var tmp = r1; - r1 = r2; - r2 = tmp; - } - if (c2 < c1) { - var tmp = c1; - c1 = c2; - c2 = tmp; - } - var objects = []; - var locations = []; - for (var r = r1; r <= r2; r++) { - for (var c = c1; c <= c2; c++) { - var location = getLocation(level, r, c); - locations.push(location); - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(objects, object); - } - } - // select the rest of any partially-selected objects - objects.forEach(function(object) { - object.locations.forEach(function(location) { - addIfNotPresent(locations, location); - }); - }); - return locations; -} - -function setHeight(newHeight, changeLog) { - if (newHeight < level.height) { - // crop - for (var r = newHeight; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - // also delete non-space tiles - paintTileAtLocation(location, SPACE, changeLog); - } - } - level.map.splice(newHeight * level.width); - } else { - // expand - for (var r = level.height; r < newHeight; r++) { - for (var c = 0; c < level.width; c++) { - level.map.push(SPACE); - } - } - } - changeLog.push(["h", level.height, newHeight]); - level.height = newHeight; -} -function setWidth(newWidth, changeLog) { - if (newWidth < level.width) { - // crop - for (var r = level.height - 1; r >= 0; r--) { - for (var c = level.width - 1; c >= newWidth; c--) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, SPACE, changeLog); - level.map.splice(location, 1); - } - } - } else { - // expand - for (var r = level.height - 1; r >= 0; r--) { - var insertionPoint = level.width * (r + 1); - for (var c = level.width; c < newWidth; c++) { - // boy is this inefficient. ... YOLO! - level.map.splice(insertionPoint, 0, SPACE); - } - } - } - - var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); - level.objects.forEach(function(object) { - object.locations = object.locations.map(transformLocation); - }); - - changeLog.push(["w", level.width, newWidth]); - level.width = newWidth; -} - -function newSnake(color, location) { - var snakes = findSnakesOfColor(color); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id !== i * snakeColors.length + color) break; - } - return { - type: SNAKE, - id: i * snakeColors.length + color, - dead: false, - locations: [location], - }; -} -function newBlock(location) { - var blocks = getBlocks(); - blocks.sort(compareId); - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id !== i) break; - } - return { - type: BLOCK, - id: i, - dead: false, // unused - locations: [location], - }; -} -function newFruit(location) { - var fruits = getObjectsOfType(FRUIT); - fruits.sort(compareId); - for (var i = 0; i < fruits.length; i++) { - if (fruits[i].id !== i) break; - } - return { - type: FRUIT, - id: i, - dead: false, // unused - locations: [location], - }; -} -function paintAtLocation(location, changeLog) { - if (typeof paintBrushTileCode === "number") { - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, paintBrushTileCode, changeLog); - } else if (paintBrushTileCode === "resize") { - var toRowcol = getRowcol(level, location); - var dr = toRowcol.r - resizeDragAnchorRowcol.r; - var dc = toRowcol.c - resizeDragAnchorRowcol.c; - resizeDragAnchorRowcol = toRowcol; - if (dr !== 0) setHeight(level.height + dr, changeLog); - if (dc !== 0) setWidth(level.width + dc, changeLog); - } else if (paintBrushTileCode === "select") { - selectionEnd = location; - } else if (paintBrushTileCode === "paste") { - var hoverRowcol = getRowcol(level, location); - var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); - pastedData.selectedLocations.forEach(function(location) { - var tileCode = pastedData.level.map[location]; - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, tileCode, changeLog); - }); - pastedData.selectedObjects.forEach(function(object) { - // refresh the ids so there are no collisions. - if (object.type === SNAKE) { - object.id = newSnake(object.id % snakeColors.length).id; - } else if (object.type === BLOCK) { - object.id = newBlock().id; - } else if (object.type === FRUIT) { - object.id = newFruit().id; - } else throw unreachable(); - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - }); - } else if (paintBrushTileCode === SNAKE) { - var oldSnakeSerialization = serializeObjectState(paintBrushObject); - if (paintBrushObject != null) { - // keep dragging - if (paintBrushObject.locations[0] === location) return; // we just did that - // watch out for self-intersection - var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); - if (selfIntersectionIndex !== -1) { - // truncate from here back - paintBrushObject.locations.splice(selfIntersectionIndex); - } - } - - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - if (paintBrushObject == null) { - var thereWereNoSnakes = countSnakes() === 0; - paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); - level.objects.push(paintBrushObject); - if (thereWereNoSnakes) activateAnySnakePlease(); - } else { - // extend le snake - paintBrushObject.locations.unshift(location); - } - changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); - } else if (paintBrushTileCode === BLOCK) { - var objectHere = findObjectAtLocation(location); - if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { - // just start editing this block - paintBrushBlockId = objectHere.id; - } else { - // make a change - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - var thisBlock = null; - if (paintBrushBlockId != null) { - thisBlock = findBlockById(paintBrushBlockId); - } - var oldBlockSerialization = serializeObjectState(thisBlock); - if (thisBlock == null) { - // create new block - removeAnyObjectAtLocation(location, changeLog); - thisBlock = newBlock(location); - level.objects.push(thisBlock); - paintBrushBlockId = thisBlock.id; - } else { - var existingIndex = thisBlock.locations.indexOf(location); - if (existingIndex !== -1) { - // reclicking part of this object means to delete just part of it. - if (thisBlock.locations.length === 1) { - // goodbye - removeObject(thisBlock, changeLog); - paintBrushBlockId = null; - } else { - thisBlock.locations.splice(existingIndex, 1); - } - } else { - // add a tile to the block - removeAnyObjectAtLocation(location, changeLog); - thisBlock.locations.push(location); - } - } - changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); - delete blockSupportRenderCache[thisBlock.id]; - } - } else if (paintBrushTileCode === FRUIT) { - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - var object = newFruit(location) - level.objects.push(object); - changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); - } else throw unreachable(); - render(); -} - -function paintTileAtLocation(location, tileCode, changeLog) { - if (level.map[location] === tileCode) return; - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; -} - -function pushUndo(undoStuff, changeLog) { - // changeLog = [ - // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], - // // player input for snake 0, dr:-1, dc:0. has no effect on state. - // // "i" is always the first change in normal player movement. - // // if a changeLog does not start with "i", then it is an editor action. - // // animationQueue and freshlyRemovedAnimatedObjects - // // are used for animating re-move. - // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 - // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] - // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] - // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] - // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] - // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. - // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. - // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. - // 10, // the last change is always a declaration of the final width of the map. - // ]; - reduceChangeLog(changeLog); - if (changeLog.length === 0) return; - changeLog.push(level.width); - undoStuff.undoStack.push(changeLog); - undoStuff.redoStack = []; - paradoxes = []; - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; - - undoStuffChanged(undoStuff); -} -function reduceChangeLog(changeLog) { - for (var i = 0; i < changeLog.length - 1; i++) { - var change = changeLog[i]; - if (change[0] === "i") { - continue; // don't reduce player input - } else if (change[0] === "h") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "h") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "w") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "w") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "w") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "h") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "m") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "m" && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (change[2] === change[3]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === change[0] && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (deepEquals(change[2], change[3])) { - // no change - changeLog.splice(i, 1); - i--; - } - } else throw unreachable(); - } -} -function undo(undoStuff) { - if (undoStuff.undoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - undoOneFrame(undoStuff); - undoStuffChanged(undoStuff); -} -function reset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.undoStack.length > 0) { - undoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); -} -function undoOneFrame(undoStuff) { - var doThis = undoStuff.undoStack.pop(); - var redoChangeLog = []; - undoChanges(doThis, redoChangeLog); - if (redoChangeLog.length > 0) { - redoChangeLog.push(level.width); - undoStuff.redoStack.push(redoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; -} -function redo(undoStuff) { - if (undoStuff.redoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - redoOneFrame(undoStuff); - undoStuffChanged(undoStuff); -} -function unreset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.redoStack.length > 0) { - redoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); - - // don't animate the last frame - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; -} -function redoOneFrame(undoStuff) { - var doThis = undoStuff.redoStack.pop(); - var undoChangeLog = []; - undoChanges(doThis, undoChangeLog); - if (undoChangeLog.length > 0) { - undoChangeLog.push(level.width); - undoStuff.undoStack.push(undoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; -} -function undoChanges(changes, changeLog) { - var widthContext = changes.pop(); - var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); - for (var i = changes.length - 1; i >= 0; i--) { - var paradoxDescription = undoChange(changes[i]); - if (paradoxDescription != null) paradoxes.push(paradoxDescription); - } - - var lastChange = changes[changes.length - 1]; - if (lastChange[0] === "i") { - // replay animation - animationQueue = lastChange[4]; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = lastChange[5]; - animationStart = new Date().getTime(); - } - - function undoChange(change) { - // note: everything here is going backwards: to -> from - if (change[0] === "i") { - // no state change, but preserve the intention. - changeLog.push(change); - return null; - } else if (change[0] === "h") { - // change height - var fromHeight = change[1]; - var toHeight = change[2]; - if (level.height !== toHeight) return "Impossible"; - setHeight(fromHeight, changeLog); - } else if (change[0] === "w") { - // change width - var fromWidth = change[1]; - var toWidth = change[2]; - if (level.width !== toWidth) return "Impossible"; - setWidth(fromWidth, changeLog); - } else if (change[0] === "m") { - // change map tile - var location = transformLocation(change[1]); - var fromTileCode = change[2]; - var toTileCode = change[3]; - if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; - if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; - paintTileAtLocation(location, fromTileCode, changeLog); - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { - // change object - var type = change[0]; - var id = change[1]; - var fromDead = change[2][0]; - var toDead = change[3][0]; - var fromLocations = change[2][1].map(transformLocation); - var toLocations = change[3][1].map(transformLocation); - if (fromLocations.filter(function(location) { return location >= level.map.length; }).length > 0) { - return "Can't move " + describe(type, id) + " out of bounds"; - } - var object = findObjectOfTypeAndId(type, id); - if (toLocations.length !== 0) { - // should exist at this location - if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; - if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; - if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; - // doit - if (fromLocations.length !== 0) { - var oldState = serializeObjectState(object); - object.locations = fromLocations; - object.dead = fromDead; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - } else { - removeObject(object, changeLog); - } - } else { - // shouldn't exist - if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; - // doit - object = { - type: type, - id: id, - dead: fromDead, - locations: fromLocations, - }; - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - } - } else throw unreachable(); - } -} -function describe(arg1, arg2) { - // describe(0) -> "Space" - // describe(SNAKE, 0) -> "Snake 0 (Red)" - // describe(object) -> "Snake 0 (Red)" - // describe(BLOCK, 1) -> "Block 1" - // describe(FRUIT) -> "Fruit" - if (typeof arg1 === "number") { - switch (arg1) { - case SPACE: return "Space"; - case WALL: return "a Wall"; - case SPIKE: return "Spikes"; - case EXIT: return "an Exit"; - case PORTAL: return "a Portal"; - default: throw unreachable(); - } - } - if (arg1 === SNAKE) { - var color = (function() { - switch (snakeColors[arg2 % snakeColors.length]) { - case "#f00": return " (Red)"; - case "#0f0": return " (Green)"; - case "#00f": return " (Blue)"; - case "#ff0": return " (Yellow)"; - default: throw unreachable(); - } - })(); - return "Snake " + arg2 + color; - } - if (arg1 === BLOCK) { - return "Block " + arg2; - } - if (arg1 === FRUIT) { - return "Fruit"; - } - if (typeof arg1 === "object") return describe(arg1.type, arg1.id); - throw unreachable(); -} - -function undoStuffChanged(undoStuff) { - var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; - document.getElementById(undoStuff.spanId).textContent = movesText; - document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; - document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; - - // render paradox display - var uniqueParadoxes = []; - var paradoxCounts = []; - paradoxes.forEach(function(paradoxDescription) { - var index = uniqueParadoxes.indexOf(paradoxDescription); - if (index !== -1) { - paradoxCounts[index] += 1; - } else { - uniqueParadoxes.push(paradoxDescription); - paradoxCounts.push(1); - } - }); - var paradoxDivContent = ""; - uniqueParadoxes.forEach(function(paradox, i) { - if (i > 0) paradoxDivContent += "
\n"; - if (paradoxCounts[i] > 1) paradoxDivContent += "(" + paradoxCounts[i] + "x) "; - paradoxDivContent += "Time Travel Paradox! " + uniqueParadoxes[i]; - }); - document.getElementById("paradoxDiv").innerHTML = paradoxDivContent; - - updateDirtyState(); - - if (unmoveStuff.redoStack.length === 0) { - document.getElementById("removeButton").classList.remove("click-me"); - } -} - -var CLEAN_NO_TIMELINES = 0; -var CLEAN_WITH_REDO = 1; -var REPLAY_DIRTY = 2; -var EDITOR_DIRTY = 3; -var dirtyState = CLEAN_NO_TIMELINES; -var editorHasBeenTouched = false; -function updateDirtyState() { - if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { - dirtyState = EDITOR_DIRTY; - } else if (unmoveStuff.undoStack.length > 0) { - dirtyState = REPLAY_DIRTY; - } else if (unmoveStuff.redoStack.length > 0) { - dirtyState = CLEAN_WITH_REDO; - } else { - dirtyState = CLEAN_NO_TIMELINES; - } - - var saveLevelButton = document.getElementById("saveLevelButton"); - // the save button clears your timelines - saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; - if (dirtyState >= EDITOR_DIRTY) { - // you should save - saveLevelButton.classList.add("click-me"); - saveLevelButton.textContent = "*" + "Save Level"; - } else { - saveLevelButton.classList.remove("click-me"); - saveLevelButton.textContent = "Save Level"; - } - - var saveProgressButton = document.getElementById("saveProgressButton"); - // you can't save a replay if your level is dirty - if (dirtyState === CLEAN_WITH_REDO) { - saveProgressButton.textContent = "Forget Progress"; - } else { - saveProgressButton.textContent = "Save Progress"; - } - saveProgressButton.disabled = dirtyState >= EDITOR_DIRTY || dirtyState === CLEAN_NO_TIMELINES; -} -function haveCheatcodesBeenUsed() { - return !unmoveStuff.undoStack.every(function(changeLog) { - // normal movement always starts with "i". - return changeLog[0][0] === "i"; - }); -} - -var persistentState = { - showEditor: false, - showGrid: false, -}; -function savePersistentState() { - localStorage.snakefall = JSON.stringify(persistentState); -} -function loadPersistentState() { - try { - persistentState = JSON.parse(localStorage.snakefall); - } catch (e) { - } - persistentState.showEditor = !!persistentState.showEditor; - persistentState.showGrid = !!persistentState.showGrid; - showEditorChanged(); -} -var isGravityEnabled = true; -function isGravity() { - return isGravityEnabled || !persistentState.showEditor; -} -var isCollisionEnabled = true; -function isCollision() { - return isCollisionEnabled || !persistentState.showEditor; -} -function isAnyCheatcodeEnabled() { - return persistentState.showEditor && ( - !isGravityEnabled || !isCollisionEnabled - ); -} - - -function showEditorChanged() { - document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor Stuff"; - ["editorDiv", "editorPane"].forEach(function(id) { - document.getElementById(id).style.display = persistentState.showEditor ? "block" : "none"; - }); - document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : "/WASD"; - - render(); -} - -function move(dr, dc) { - if (!isAlive()) return; - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; - animationStart = new Date().getTime(); - var activeSnake = findActiveSnake(); - var headRowcol = getRowcol(level, activeSnake.locations[0]); - var newRowcol = {r:headRowcol.r + dr, c:headRowcol.c + dc}; - if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; - var newLocation = getLocation(level, newRowcol.r, newRowcol.c); - var changeLog = []; - - // The changeLog for a player movement starts with the input - // when playing normally. - if (!isAnyCheatcodeEnabled()) { - changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); - } - - var ate = false; - var pushedObjects = []; - - if (isCollision()) { - var newTile = level.map[newLocation]; - if (!isTileCodeAir(newTile)) return; // can't go through that tile - var otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { - if (otherObject === activeSnake) return; // can't push yourself - if (otherObject.type === FRUIT) { - // eat - removeObject(otherObject, changeLog); - ate = true; - } else { - // push objects - if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; - } - } - } - - // slither forward - var activeSnakeOldState = serializeObjectState(activeSnake); - var size1 = activeSnake.locations.length === 1; - var slitherAnimations = [ - 70, - [ - // size-1 snakes really do more of a move than a slither - size1 ? MOVE_SNAKE : SLITHER_HEAD, - activeSnake.id, - dr, - dc, - ] - ]; - activeSnake.locations.unshift(newLocation); - if (!ate) { - // drag your tail forward - var oldRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 1]); - var newRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 2]); - if (!size1) { - slitherAnimations.push([ - SLITHER_TAIL, - activeSnake.id, - newRowcol.r - oldRowcol.r, - newRowcol.c - oldRowcol.c, - ]); - } - activeSnake.locations.pop(); - } - changeLog.push([activeSnake.type, activeSnake.id, activeSnakeOldState, serializeObjectState(activeSnake)]); - - // did you just push your face into a portal? - var portalLocations = getActivePortalLocations(); - var portalActivationLocations = []; - if (portalLocations.indexOf(newLocation) !== -1) { - portalActivationLocations.push(newLocation); - } - // push everything, too - moveObjects(pushedObjects, dr, dc, portalLocations, portalActivationLocations, changeLog, slitherAnimations); - animationQueue.push(slitherAnimations); - - // gravity loop - var stateToAnimationIndex = {}; - if (isGravity()) for (var fallHeight = 1;; fallHeight++) { - var serializedState = serializeObjects(level.objects); - var infiniteLoopStartIndex = stateToAnimationIndex[serializedState]; - if (infiniteLoopStartIndex != null) { - // infinite loop - animationQueue.push([0, [INFINITE_LOOP, animationQueue.length - infiniteLoopStartIndex]]); - break; - } else { - stateToAnimationIndex[serializedState] = animationQueue.length; - } - // do portals separate from falling logic - if (portalActivationLocations.length === 1) { - var portalAnimations = [500]; - if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { - animationQueue.push(portalAnimations); - } - portalActivationLocations = []; - } - // now do falling logic - var didAnything = false; - var fallingAnimations = [ - 70 / Math.sqrt(fallHeight), - ]; - var exitAnimationQueue = []; - - // check for exit - if (!isUneatenFruit()) { - var snakes = getSnakes(); - for (var i = 0; i < snakes.length; i++) { - var snake = snakes[i]; - if (level.map[snake.locations[0]] === EXIT) { - // (one of) you made it! - removeAnimatedObject(snake, changeLog); - exitAnimationQueue.push([ - 200, - [EXIT_SNAKE, snake.id, 0, 0], - ]); - didAnything = true; - } - } - } - - // fall - var dyingObjects = []; - var fallingObjects = level.objects.filter(function(object) { - if (object.type === FRUIT) return; // can't fall - var theseDyingObjects = []; - if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; - // this object can fall. maybe more will fall with it too. we'll check those separately. - theseDyingObjects.forEach(function(object) { - addIfNotPresent(dyingObjects, object); - }); - return true; - }); - if (dyingObjects.length > 0) { - var anySnakesDied = false; - dyingObjects.forEach(function(object) { - if (object.type === SNAKE) { - // look what you've done - var oldState = serializeObjectState(object); - object.dead = true; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - anySnakesDied = true; - } else if (object.type === BLOCK) { - // a box fell off the world - removeAnimatedObject(object, changeLog); - removeFromArray(fallingObjects, object); - exitAnimationQueue.push([ - 200, - [ - DIE_BLOCK, - object.id, - 0, 0 - ], - ]); - didAnything = true; - } else throw unreachable(); - }); - if (anySnakesDied) break; - } - if (fallingObjects.length > 0) { - moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); - didAnything = true; - } - - if (!didAnything) break; - Array.prototype.push.apply(animationQueue, exitAnimationQueue); - if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); - } - - pushUndo(unmoveStuff, changeLog); - render(); -} - -function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects) { - // pusher can be null (for gravity) - pushedObjects.push(pushedObject); - // find forward locations - var forwardLocations = []; - for (var i = 0; i < pushedObjects.length; i++) { - pushedObject = pushedObjects[i]; - for (var j = 0; j < pushedObject.locations.length; j++) { - var rowcol = getRowcol(level, pushedObject.locations[j]); - var forwardRowcol = {r:rowcol.r + dr, c:rowcol.c + dc}; - if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { - if (dyingObjects == null) { - // can't push things out of bounds - return false; - } else { - // this thing is going to fall out of bounds - addIfNotPresent(dyingObjects, pushedObject); - addIfNotPresent(pushedObjects, pushedObject); - continue; - } - } - var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); - var yetAnotherObject = findObjectAtLocation(forwardLocation); - if (yetAnotherObject != null) { - if (yetAnotherObject.type === FRUIT) { - // not pushable - return false; - } - if (yetAnotherObject === pusher) { - // indirect pushing ourselves. - // special check for when we're indirectly pushing the tip of our own tail. - if (forwardLocation === pusher.locations[pusher.locations.length -1]) { - // for some reason this is ok. - continue; - } - return false; - } - addIfNotPresent(pushedObjects, yetAnotherObject); - } else { - addIfNotPresent(forwardLocations, forwardLocation); - } - } - } - // check forward locations - for (var i = 0; i < forwardLocations.length; i++) { - var forwardLocation = forwardLocations[i]; - // many of these locations can be inside objects, - // but that means the tile must be air, - // and we already know pushing that object. - var tileCode = level.map[forwardLocation]; - if (!isTileCodeAir(tileCode)) { - if (dyingObjects != null) { - if (tileCode === SPIKE) { - // uh... which object was this again? - var deadObject = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); - if (deadObject.type === SNAKE) { - // ouch! - addIfNotPresent(dyingObjects, deadObject); - continue; - } - } - } - // can't push into something solid - return false; - } - } - // the push is go - return true; -} - -function activateAnySnakePlease() { - var snakes = getSnakes(); - if (snakes.length === 0) return; // nope.avi - activeSnakeId = snakes[0].id; -} - -function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations, changeLog, animations) { - objects.forEach(function(object) { - var oldState = serializeObjectState(object); - var oldPortals = getSetIntersection(portalLocations, object.locations); - for (var i = 0; i < object.locations.length; i++) { - object.locations[i] = offsetLocation(object.locations[i], dr, dc); - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - animations.push([ - "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK - object.id, - dr, - dc, - ]); - - var newPortals = getSetIntersection(portalLocations, object.locations); - var activatingPortals = newPortals.filter(function(portalLocation) { - return oldPortals.indexOf(portalLocation) === -1; - }); - if (activatingPortals.length === 1) { - // exactly one new portal we're touching. activate it - portalActivationLocations.push(activatingPortals[0]); - } - }); -} - -function activatePortal(portalLocations, portalLocation, animations, changeLog) { - var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; - var portalRowcol = getRowcol(level, portalLocation); - var otherPortalRowcol = getRowcol(level, otherPortalLocation); - var delta = {r:otherPortalRowcol.r - portalRowcol.r, c:otherPortalRowcol.c - portalRowcol.c}; - - var object = findObjectAtLocation(portalLocation); - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r + delta.r; - var c = rowcol.c + delta.c; - if (!isInBounds(level, r, c)) return false; // out of bounds - newLocations.push(getLocation(level, r, c)); - } - - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (!isTileCodeAir(level.map[location])) return false; // blocked by tile - var otherObject = findObjectAtLocation(location); - if (otherObject != null && otherObject !== object) return false; // blocked by object - } - - // zappo presto! - var oldState = serializeObjectState(object); - object.locations = newLocations; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - animations.push([ - "t" + object.type, // TELEPORT_SNAKE | TELEPORT_BLOCK - object.id, - delta.r, - delta.c, - ]); - return true; -} - -function isTileCodeAir(tileCode) { - return tileCode === SPACE || tileCode === EXIT || tileCode === PORTAL; -} - -function addIfNotPresent(array, element) { - if (array.indexOf(element) !== -1) return; - array.push(element); -} -function removeAnyObjectAtLocation(location, changeLog) { - var object = findObjectAtLocation(location); - if (object != null) removeObject(object, changeLog); -} -function removeAnimatedObject(object, changeLog) { - removeObject(object, changeLog); - freshlyRemovedAnimatedObjects.push(object); -} -function removeObject(object, changeLog) { - removeFromArray(level.objects, object); - changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0,[]]]); - if (object.type === SNAKE && object.id === activeSnakeId) { - activateAnySnakePlease(); - } - if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { - // no longer editing an object that doesn't exit - paintBrushBlockId = null; - } - if (object.type === BLOCK) { - delete blockSupportRenderCache[object.id]; - } -} -function removeFromArray(array, element) { - var index = array.indexOf(element); - if (index === -1) throw unreachable(); - array.splice(index, 1); -} -function findActiveSnake() { - var snakes = getSnakes(); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) return snakes[i]; - } - throw unreachable(); -} -function findBlockById(id) { - return findObjectOfTypeAndId(BLOCK, id); -} -function findSnakesOfColor(color) { - return level.objects.filter(function(object) { - if (object.type !== SNAKE) return false; - return object.id % snakeColors.length === color; - }); -} -function findObjectOfTypeAndId(type, id) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.type === type && object.id === id) return object; - } - return null; -} -function findObjectAtLocation(location) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.locations.indexOf(location) !== -1) - return object; - } - return null; -} -function isUneatenFruit() { - return getObjectsOfType(FRUIT).length > 0; -} -function getActivePortalLocations() { - var portalLocations = getPortalLocations(); - if (portalLocations.length !== 2) return []; // nice try - return portalLocations; -} -function getPortalLocations() { - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === PORTAL) result.push(i); - } - return result; -} -function countSnakes() { - return getSnakes().length; -} -function getSnakes() { - return getObjectsOfType(SNAKE); -} -function getBlocks() { - return getObjectsOfType(BLOCK); -} -function getObjectsOfType(type) { - return level.objects.filter(function(object) { - return object.type == type; - }); -} -function isDead() { - if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; - return getSnakes().filter(function(snake) { - return !!snake.dead; - }).length > 0; -} -function isAlive() { - return countSnakes() > 0 && !isDead(); -} - -var snakeColors = [ - "#f00", - "#0f0", - "#00f", - "#ff0", -]; -var blockForeground = ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"]; -var blockBackground = ["#853641","#963c84","#753d88","#5d3a96","#3a3990"]; - -var activeSnakeId = null; - -var SLITHER_HEAD = "sh"; -var SLITHER_TAIL = "st"; -var MOVE_SNAKE = "ms"; -var MOVE_BLOCK = "mb"; -var TELEPORT_SNAKE = "ts"; -var TELEPORT_BLOCK = "tb"; -var EXIT_SNAKE = "es"; -var DIE_SNAKE = "ds"; -var DIE_BLOCK = "db"; -var INFINITE_LOOP = "il"; -var animationQueue = [ - // // sequence of disjoint animation groups. - // // each group completes before the next begins. - // [ - // 70, // duration of this animation group - // // multiple things to animate simultaneously - // [ - // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, - // objectId, - // dr, - // dc, - // ], - // [ - // INFINITE_LOOP, - // loopSizeNotIncludingThis, - // ], - // ], -]; -var animationQueueCursor = 0; -var animationStart = null; // new Date().getTime() -var animationProgress; // 0.0 <= x < 1.0 -var freshlyRemovedAnimatedObjects = []; - -// render the support beams for blocks into a temporary buffer, and remember it. -// this is due to stencil buffers causing slowdown on some platforms. see #25. -var blockSupportRenderCache = { - // id: canvas, - // "0": document.createElement("canvas"), -}; - -function render() { - if (level == null) return; - if (animationQueueCursor < animationQueue.length) { - var animationDuration = animationQueue[animationQueueCursor][0]; - animationProgress = (new Date().getTime() - animationStart) / animationDuration; - if (animationProgress >= 1.0) { - // animation group complete - animationProgress -= 1.0; - animationQueueCursor++; - if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { - var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; - animationQueueCursor -= infiniteLoopSize; - } - animationStart = new Date().getTime(); - } - } - if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; - canvas.width = tileSize * level.width; - canvas.height = tileSize * level.height; - var context = canvas.getContext("2d"); - context.fillStyle = "#88f"; // sky - context.fillRect(0, 0, canvas.width, canvas.height); - - if (persistentState.showGrid && !persistentState.showEditor) { - drawGrid(); - } - - var activePortalLocations = getActivePortalLocations(); - - // normal render - renderLevel(); - - if (persistentState.showGrid && persistentState.showEditor) { - drawGrid(); - } - // active snake halo - if (countSnakes() !== 0 && isAlive()) { - var activeSnake = findActiveSnake(); - var activeSnakeRowcol = getRowcol(level, activeSnake.locations[0]); - drawCircle(activeSnakeRowcol.r, activeSnakeRowcol.c, 2, "rgba(256,256,256,0.3)"); - } - - if (persistentState.showEditor) { - if (paintBrushTileCode === BLOCK) { - if (paintBrushBlockId != null) { - // fade everything else away - context.fillStyle = "rgba(0, 0, 0, 0.8)"; - context.fillRect(0, 0, canvas.width, canvas.height); - // and render just this object in focus - var activeBlock = findBlockById(paintBrushBlockId); - renderLevel([activeBlock]); - } - } else if (paintBrushTileCode === "select") { - getSelectedLocations().forEach(function(location) { - var rowcol = getRowcol(level, location); - drawRect(rowcol.r, rowcol.c, "rgba(128, 128, 128, 0.3)"); - }); - } - } - - // serialize - if (!isDead()) { - var serialization = stringifyLevel(level); - document.getElementById("serializationTextarea").value = serialization; - var link = location.href.substring(0, location.href.length - location.hash.length); - link += "#level=" + compressSerialization(serialization); - document.getElementById("shareLinkTextbox").value = link; - } - - // throw this in there somewhere - document.getElementById("showGridButton").textContent = (persistentState.showGrid ? "Hide" : "Show") + " Grid"; - - if (animationProgress < 1.0) requestAnimationFrame(render); - return; // this is the end of the function proper - - function renderLevel(onlyTheseObjects) { - var objects = level.objects; - if (onlyTheseObjects != null) { - objects = onlyTheseObjects; - } else { - objects = level.objects.concat(freshlyRemovedAnimatedObjects.filter(function(object) { - // the object needs to have a future removal animation, or else, it's gone already. - return hasFutureRemoveAnimation(object); - })); - } - // begin by rendering the background connections for blocks - objects.forEach(function(object) { - if (object.type !== BLOCK) return; - var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); - var minR = Infinity; - var maxR = -Infinity; - var minC = Infinity; - var maxC = -Infinity; - object.locations.forEach(function(location) { - var rowcol = getRowcol(level, location); - if (rowcol.r < minR) minR = rowcol.r; - if (rowcol.r > maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var image = blockSupportRenderCache[object.id]; - if (image == null) { - // render the support beams to a buffer - blockSupportRenderCache[object.id] = image = document.createElement("canvas"); - image.width = (maxC - minC + 1) * tileSize; - image.height = (maxR - minR + 1) * tileSize; - var bufferContext = image.getContext("2d"); - // Make a stencil that excludes the insides of blocks. - // Then when we render the support beams, we won't see the supports inside the block itself. - bufferContext.beginPath(); - // Draw a path around the whole screen in the opposite direction as the rectangle paths below. - // This means that the below rectangles will be removing area from the greater rectangle. - bufferContext.rect(image.width, 0, -image.width, image.height); - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r - minR; - var c = rowcol.c - minC; - bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); - } - bufferContext.clip(); - for (var i = 0; i < object.locations.length - 1; i++) { - var rowcol1 = getRowcol(level, object.locations[i]); - rowcol1.r -= minR; - rowcol1.c -= minC; - var rowcol2 = getRowcol(level, object.locations[i + 1]); - rowcol2.r -= minR; - rowcol2.c -= minC; - var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; - drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockBackground[object.id % blockBackground.length]); - drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockBackground[object.id % blockBackground.length]); - } - } - var r = minR + animationDisplacementRowcol.r; - var c = minC + animationDisplacementRowcol.c; - context.drawImage(image, c * tileSize, r * tileSize); - }); - - // terrain - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - var tileCode = level.map[location]; - drawTile(tileCode, r, c, level, location); - } - } - } - - // objects - objects.forEach(drawObject); - - // banners - if (countSnakes() === 0) { - context.fillStyle = "#ff0"; - context.font = "100px Arial"; - context.fillText("test!", 0, canvas.height / 2); - } - if (isDead()) { - context.fillStyle = "#f00"; - context.font = "100px Arial"; - context.fillText("You Dead!", 0, canvas.height / 2); - } - - // editor hover - if (persistentState.showEditor && paintBrushTileCode != null && hoverLocation != null && hoverLocation < level.map.length) { - - var savedContext = context; - var buffer = document.createElement("canvas"); - buffer.width = canvas.width; - buffer.height = canvas.height; - context = buffer.getContext("2d"); - - var hoverRowcol = getRowcol(level, hoverLocation); - var objectHere = findObjectAtLocation(hoverLocation); - if (typeof paintBrushTileCode === "number") { - if (level.map[hoverLocation] !== paintBrushTileCode) { - drawTile(paintBrushTileCode, hoverRowcol.r, hoverRowcol.c, level, hoverLocation); - } - } else if (paintBrushTileCode === SNAKE) { - if (!(objectHere != null && objectHere.type === SNAKE && objectHere.id === paintBrushSnakeColorIndex)) { - drawObject(newSnake(paintBrushSnakeColorIndex, hoverLocation)); - } - } else if (paintBrushTileCode === BLOCK) { - if (!(objectHere != null && objectHere.type === BLOCK && objectHere.id === paintBrushBlockId)) { - drawObject(newBlock(hoverLocation)); - } - } else if (paintBrushTileCode === FRUIT) { - if (!(objectHere != null && objectHere.type === FRUIT)) { - drawObject(newFruit(hoverLocation)); - } - } else if (paintBrushTileCode === "resize") { - void 0; // do nothing - } else if (paintBrushTileCode === "select") { - void 0; // do nothing - } else if (paintBrushTileCode === "paste") { - // show what will be pasted if you click - var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); - pastedData.selectedLocations.forEach(function(location) { - var tileCode = pastedData.level.map[location]; - var rowcol = getRowcol(level, location); - drawTile(tileCode, rowcol.r, rowcol.c, pastedData.level, location); - }); - pastedData.selectedObjects.forEach(drawObject); - } else throw unreachable(); - - context = savedContext; - context.save(); - context.globalAlpha = 0.2; - context.drawImage(buffer, 0, 0); - context.restore(); - } - } - function drawTile(tileCode, r, c, level, location) { - switch (tileCode) { - case SPACE: - break; - case WALL: - drawWall(r, c, getAdjacentTiles()); - break; - case SPIKE: - drawSpikes(r, c, level); - break; - case EXIT: - var radiusFactor = isUneatenFruit() ? 0.7 : 1.2; - drawQuarterPie(r, c, radiusFactor, "#f00", 0); - drawQuarterPie(r, c, radiusFactor, "#0f0", 1); - drawQuarterPie(r, c, radiusFactor, "#00f", 2); - drawQuarterPie(r, c, radiusFactor, "#ff0", 3); - break; - case PORTAL: - drawCircle(r, c, 0.8, "#888"); - drawCircle(r, c, 0.6, "#111"); - if (activePortalLocations.indexOf(location) !== -1) drawCircle(r, c, 0.3, "#666"); - break; - default: throw unreachable(); - } - function getAdjacentTiles() { - return [ - [getTile(r - 1, c - 1), - getTile(r - 1, c + 0), - getTile(r - 1, c + 1)], - [getTile(r + 0, c - 1), - null, - getTile(r + 0, c + 1)], - [getTile(r + 1, c - 1), - getTile(r + 1, c + 0), - getTile(r + 1, c + 1)], - ]; - } - function getTile(r, c) { - if (!isInBounds(level, r, c)) return null; - return level.map[getLocation(level, r, c)]; - } - } - - function drawObject(object) { - switch (object.type) { - case SNAKE: - var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); - var lastRowcol = null - var color = snakeColors[object.id % snakeColors.length]; - var headRowcol; - for (var i = 0; i <= object.locations.length; i++) { - var animation; - var rowcol; - if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { - // animate head slithering forward - rowcol = getRowcol(level, object.locations[i]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else if (i === object.locations.length) { - // animated tail? - if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { - // animate tail slithering to catch up - rowcol = getRowcol(level, object.locations[i - 1]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else { - // no animated tail needed - break; - } - } else { - rowcol = getRowcol(level, object.locations[i]); - } - if (object.dead) rowcol.r += 0.5; - rowcol.r += animationDisplacementRowcol.r; - rowcol.c += animationDisplacementRowcol.c; - if (i === 0) { - // head - headRowcol = rowcol; - drawDiamond(rowcol.r, rowcol.c, color); - } else { - // middle - var cx = (rowcol.c + 0.5) * tileSize; - var cy = (rowcol.r + 0.5) * tileSize; - context.fillStyle = color; - var orientation; - if (lastRowcol.r < rowcol.r) { - orientation = 0; - context.beginPath(); - context.moveTo((lastRowcol.c + 0) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.lineTo((lastRowcol.c + 1) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.arc(cx, cy, tileSize/2, 0, Math.PI); - context.fill(); - } else if (lastRowcol.r > rowcol.r) { - orientation = 2; - context.beginPath(); - context.moveTo((lastRowcol.c + 1) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.lineTo((lastRowcol.c + 0) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.arc(cx, cy, tileSize/2, Math.PI, 0); - context.fill(); - } else if (lastRowcol.c < rowcol.c) { - orientation = 3; - context.beginPath(); - context.moveTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 1) * tileSize); - context.lineTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 0) * tileSize); - context.arc(cx, cy, tileSize/2, 1.5 * Math.PI, 2.5 * Math.PI); - context.fill(); - } else if (lastRowcol.c > rowcol.c) { - orientation = 1; - context.beginPath(); - context.moveTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 0) * tileSize); - context.lineTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 1) * tileSize); - context.arc(cx, cy, tileSize/2, 2.5 * Math.PI, 1.5 * Math.PI); - context.fill(); - } - } - lastRowcol = rowcol; - } - // eye - if (object.id === activeSnakeId) { - drawCircle(headRowcol.r, headRowcol.c, 0.5, "#fff"); - drawCircle(headRowcol.r, headRowcol.c, 0.2, "#000"); - } - break; - case BLOCK: - drawBlock(object); - break; - case FRUIT: - var rowcol = getRowcol(level, object.locations[0]); - drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); - break; - default: throw unreachable(); - } - } - - function drawWall(r, c, adjacentTiles) { - drawRect(r, c, "#844204"); // dirt - context.fillStyle = "#282"; // grass - drawTileOutlines(r, c, isWall, 0.2); - - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; - } - } - function drawTileOutlines(r, c, isOccupied, outlineThickness) { - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - var complementPixels = (1 - 2 * outlineThickness) * tileSize; - if (!isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - if (!isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (!isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); - } - function drawSpikes(r, c) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = "#333"; - context.beginPath(); - context.moveTo(x + tileSize * 0.3, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.4, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.5, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.6, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.3); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3); - context.fill(); - } - function drawConnector(context, r1, c1, r2, c2, color) { - // either r1 and r2 or c1 and c2 must be equal - if (r1 > r2 || c1 > c2) { - var rTmp = r1; - var cTmp = c1; - r1 = r2; - c1 = c2; - r2 = rTmp; - c2 = cTmp; - } - var xLo = (c1 + 0.4) * tileSize; - var yLo = (r1 + 0.4) * tileSize; - var xHi = (c2 + 0.6) * tileSize; - var yHi = (r2 + 0.6) * tileSize; - context.fillStyle = color; - context.fillRect(xLo, yLo, xHi - xLo, yHi - yLo); - } - function drawBlock(block) { - var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); - var rowcols = block.locations.map(function(location) { - return getRowcol(level, location); - }); - rowcols.forEach(function(rowcol) { - var r = rowcol.r + animationDisplacementRowcol.r; - var c = rowcol.c + animationDisplacementRowcol.c; - context.fillStyle = blockForeground[block.id % blockForeground.length]; - drawTileOutlines(r, c, isAlsoThisBlock, 0.3); - function isAlsoThisBlock(dc, dr) { - for (var i = 0; i < rowcols.length; i++) { - var otherRowcol = rowcols[i]; - if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; - } - return false; - } - }); - } - function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { - var cx = (c + 0.5) * tileSize; - var cy = (r + 0.5) * tileSize; - context.fillStyle = fillStyle; - context.beginPath(); - context.moveTo(cx, cy); - context.arc(cx, cy, radiusFactor * tileSize/2, quadrant * Math.PI/2, (quadrant + 1) * Math.PI/2); - context.fill(); - } - function drawDiamond(r, c, fillStyle) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = fillStyle; - context.beginPath(); - context.moveTo(x + tileSize/2, y); - context.lineTo(x + tileSize, y + tileSize/2); - context.lineTo(x + tileSize/2, y + tileSize); - context.lineTo(x, y + tileSize/2); - context.lineTo(x + tileSize/2, y); - context.fill(); - } - function drawCircle(r, c, radiusFactor, fillStyle) { - context.fillStyle = fillStyle; - context.beginPath(); - context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize/2 * radiusFactor, 0, 2*Math.PI); - context.fill(); - } - function drawRect(r, c, fillStyle) { - context.fillStyle = fillStyle; - context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); - } - - function drawGrid() { - var buffer = document.createElement("canvas"); - buffer.width = canvas.width; - buffer.height = canvas.height; - var localContext = buffer.getContext("2d"); - - localContext.strokeStyle = "#fff"; - localContext.beginPath(); - for (var r = 0; r < level.height; r++) { - localContext.moveTo(0, tileSize*r); - localContext.lineTo(tileSize*level.width, tileSize*r); - } - for (var c = 0; c < level.width; c++) { - localContext.moveTo(tileSize*c, 0); - localContext.lineTo(tileSize*c, tileSize*level.height); - } - localContext.stroke(); - - context.save(); - context.globalAlpha = 0.4; - context.drawImage(buffer, 0, 0); - context.restore(); - } -} - -function findAnimation(animationTypes, objectId) { - if (animationQueueCursor === animationQueue.length) return null; - var currentAnimation = animationQueue[animationQueueCursor]; - for (var i = 1; i < currentAnimation.length; i++) { - var animation = currentAnimation[i]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === objectId) { - return animation; - } - } -} -function findAnimationDisplacementRowcol(objectType, objectId) { - var dr = 0; - var dc = 0; - var animationTypes = [ - "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK - "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK - ]; - // skip the current one - for (var i = animationQueueCursor + 1; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === objectId) { - dr += animation[2]; - dc += animation[3]; - } - } - } - var movementAnimation = findAnimation(animationTypes, objectId); - if (movementAnimation != null) { - dr += movementAnimation[2] * (1 - animationProgress); - dc += movementAnimation[3] * (1 - animationProgress); - } - return {r: -dr, c: -dc}; -} -function hasFutureRemoveAnimation(object) { - var animationTypes = [ - EXIT_SNAKE, - DIE_BLOCK, - ]; - for (var i = animationQueueCursor; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === object.id) { - return true; - } - } - } -} - -function previewPaste(hoverR, hoverC) { - var offsetR = hoverR - clipboardOffsetRowcol.r; - var offsetC = hoverC - clipboardOffsetRowcol.c; - - var newLevel = JSON.parse(JSON.stringify(level)); - var selectedLocations = []; - var selectedObjects = []; - clipboardData.selectedLocations.forEach(function(location) { - var tileCode = clipboardData.level.map[location]; - var rowcol = getRowcol(clipboardData.level, location); - var r = rowcol.r + offsetR; - var c = rowcol.c + offsetC; - if (!isInBounds(newLevel, r, c)) return; - var newLocation = getLocation(newLevel, r, c); - newLevel.map[newLocation] = tileCode; - selectedLocations.push(newLocation); - }); - clipboardData.selectedObjects.forEach(function(object) { - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(clipboardData.level, object.locations[i]); - rowcol.r += offsetR; - rowcol.c += offsetC; - if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { - // this location is oob - if (object.type === SNAKE) { - // snakes must be completely in bounds - return; - } - // just skip it - continue; - } - var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); - newLocations.push(newLocation); - } - if (newLocations.length === 0) return; // can't have a non-present object - var newObject = JSON.parse(JSON.stringify(object)); - newObject.locations = newLocations; - selectedObjects.push(newObject); - }); - return { - level: newLevel, - selectedLocations: selectedLocations, - selectedObjects: selectedObjects, - }; -} - -function getNaiveOrthogonalPath(a, b) { - // does not include a, but does include b. - var rowcolA = getRowcol(level, a); - var rowcolB = getRowcol(level, b); - var path = []; - if (rowcolA.r < rowcolB.r) { - for (var r = rowcolA.r; r < rowcolB.r; r++) { - path.push(getLocation(level, r + 1, rowcolA.c)); - } - } else { - for (var r = rowcolA.r; r > rowcolB.r; r--) { - path.push(getLocation(level, r - 1, rowcolA.c)); - } - } - if (rowcolA.c < rowcolB.c) { - for (var c = rowcolA.c; c < rowcolB.c; c++) { - path.push(getLocation(level, rowcolB.r, c + 1)); - } - } else { - for (var c = rowcolA.c; c > rowcolB.c; c--) { - path.push(getLocation(level, rowcolB.r, c - 1)); - } - } - return path; -} -function identityFunction(x) { - return x; -} -function compareId(a, b) { - return operatorCompare(a.id, b.id); -} -function operatorCompare(a, b) { - return a < b ? -1 : a > b ? 1 : 0; -} -function clamp(value, min, max) { - if (value < min) return min; - if (value > max) return max; - return value; -} -function copyArray(array) { - return array.map(identityFunction); -} -function getSetIntersection(array1, array2) { - if (array1.length * array2.length === 0) return []; - return array1.filter(function(x) { return array2.indexOf(x) !== -1; }); -} -function makeScaleCoordinatesFunction(width1, width2) { - return function(location) { - return location + (width2 - width1) * Math.floor(location / width1); - }; -} - -var expectHash; -window.addEventListener("hashchange", function() { - if (location.hash === expectHash) { - // We're in the middle of saveLevel() or saveReplay(). - // Don't react to that event. - expectHash = null; - return; - } - // The user typed into the url bar or used Back/Forward browser buttons, etc. - loadFromLocationHash(); -}); -function loadFromLocationHash() { - var hashSegments = location.hash.split("#"); - hashSegments.shift(); // first element is always "" - if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; - var hashPairs = hashSegments.map(function(segment) { - var equalsIndex = segment.indexOf("="); - if (equalsIndex === -1) return ["", segment]; // bad - return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; - }); - - if (hashPairs[0][0] !== "level") return false; - try { - var level = parseLevel(hashPairs[0][1]); - } catch (e) { - alert(e); - return false; - } - loadLevel(level); - if (hashPairs.length > 1) { - try { - if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); - parseAndLoadReplay(hashPairs[1][1]); - } catch (e) { - alert(e); - return false; - } - } - return true; -} - -// run test suite -var testTime = new Date().getTime(); -if (compressSerialization(stringifyLevel(parseLevel(testLevel_v0))) !== testLevel_v0_converted) throw new Error("v0 level conversion is broken"); -// ask the debug console for this variable if you're concerned with how much time this wastes. -testTime = new Date().getTime() - testTime; - -loadPersistentState(); -if (!loadFromLocationHash()) { - loadLevel(parseLevel(exampleLevel)); -} From ed80174d0843541e074e565be82b7e746f078755 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 15:57:44 -0500 Subject: [PATCH 009/577] Create a.js --- a.js | 3059 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 3059 insertions(+) create mode 100644 a.js diff --git a/a.js b/a.js new file mode 100644 index 00000000..3088eecc --- /dev/null +++ b/a.js @@ -0,0 +1,3059 @@ +function unreachable() { return new Error("unreachable"); } +if (typeof VERSION !== "undefined") { + document.getElementById("versionSpan").innerHTML = + '' + VERSION.tag + ''; +} + +var img3 = document.createElement('img'); //Gooby +img3.src = '/Snakefall/Snakebird Images/Cherry2.png'; + +var canvas = document.getElementById("canvas"); + +// tile codes +var SPACE = 0; +var WALL = 1; +var SPIKE = 2; +var FRUIT_v0 = 3; // legacy +var EXIT = 4; +var PORTAL = 5; +var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL]; //Gooby + +// object types +var SNAKE = "s"; +var BLOCK = "b"; +var FRUIT = "f"; + +var tileSize = 30; +var level; +var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; +var uneditStuff = {undoStack:[], redoStack:[], spanId:"editsSpan", undoButtonId:"uneditButton", redoButtonId:"reeditButton"}; +var paradoxes = []; +function loadLevel(newLevel) { + level = newLevel; + currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); + + activateAnySnakePlease(); + unmoveStuff.undoStack = []; + unmoveStuff.redoStack = []; + undoStuffChanged(unmoveStuff); + uneditStuff.undoStack = []; + uneditStuff.redoStack = []; + undoStuffChanged(uneditStuff); + blockSupportRenderCache = {}; + render(); +} + + +var magicNumber_v0 = "3tFRIoTU"; +var magicNumber = "HyRr4JK1"; +var exampleLevel = magicNumber_v0 + "&" + + "17&31" + + "?" + + "0000000000000000000000000000000" + + "0000000000000000000000000000000" + + "0000000000000000000000000000000" + + "0000000000000000000000000000000" + + "0000000000000000000000000000000" + + "0000000000000000000000000000000" + + "0000000000000000000040000000000" + + "0000000000000110000000000000000" + + "0000000000000111100000000000000" + + "0000000000000011000000000000000" + + "0000000000000010000010000000000" + + "0000000000000010100011000000000" + + "0000001111111000110000000110000" + + "0000011111111111111111111110000" + + "0000011111111101111111111100000" + + "0000001111111100111111111100000" + + "0000001111111000111111111100000" + + "/" + + "s0 ?351&350&349/" + + "f0 ?328/" + + "f1 ?366/"; + +var testLevel_v0 = "3tFRIoTU&5&5?0005*00300024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/"; +var testLevel_v0_converted = "HyRr4JK1&5&5?0005*4024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/f0?8/"; + +function parseLevel(string) { + // magic number + var cursor = 0; + skipWhitespace(); + var versionTag = string.substr(cursor, magicNumber.length); + switch (versionTag) { + case magicNumber_v0: + case magicNumber: break; + default: throw new Error("not a snakefall level"); + } + cursor += magicNumber.length; + consumeKeyword("&"); + + var level = { + height: -1, + width: -1, + map: [], + objects: [], + }; + + // height, width + level.height = readInt(); + consumeKeyword("&"); + level.width = readInt(); + + // map + var mapData = readRun(); + mapData = decompressSerialization(mapData); + if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); + var upconvertedObjects = []; + var fruitCount = 0; + for (var i = 0; i < mapData.length; i++) { + var tileCode = mapData[i].charCodeAt(0) - "0".charCodeAt(0); + if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { + // fruit used to be a tile code. now it's an object. + upconvertedObjects.push({ + type: FRUIT, + id: fruitCount++, + dead: false, // unused + locations: [i], + }); + tileCode = SPACE; + } + if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); + level.map.push(tileCode); + } + + // objects + skipWhitespace(); + while (cursor < string.length) { + var object = { + type: "?", + id: -1, + dead: false, + locations: [], + }; + + // type + object.type = string[cursor]; + var locationsLimit; + if (object.type === SNAKE) locationsLimit = -1; + else if (object.type === BLOCK) locationsLimit = -1; + else if (object.type === FRUIT) locationsLimit = 1; + else throw parserError("expected object type code"); + cursor += 1; + + // id + object.id = readInt(); + + // locations + var locationsData = readRun(); + var locationStrings = locationsData.split("&"); + if (locationStrings.length === 0) throw parserError("locations must be non-empty"); + if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); + + locationStrings.forEach(function(locationString) { + var location = parseInt(locationString); + if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); + object.locations.push(location); + }); + + level.objects.push(object); + skipWhitespace(); + } + for (var i = 0; i < upconvertedObjects.length; i++) { + level.objects.push(upconvertedObjects[i]); + } + + return level; + + function skipWhitespace() { + while (" \n\t\r".indexOf(string[cursor]) !== -1) { + cursor += 1; + } + } + function consumeKeyword(keyword) { + skipWhitespace(); + if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); + cursor += 1; + } + function readInt() { + skipWhitespace(); + for (var i = cursor; i < string.length; i++) { + if ("0123456789".indexOf(string[i]) === -1) break; + } + var substring = string.substring(cursor, i); + if (substring.length === 0) throw parserError("expected int"); + cursor = i; + return parseInt(substring, 10); + } + function readRun() { + consumeKeyword("?"); + var endIndex = string.indexOf("/", cursor); + var substring = string.substring(cursor, endIndex); + cursor = endIndex + 1; + return substring; + } + function parserError(message) { + return new Error("parse error at position " + cursor + ": " + message); + } +} + +function stringifyLevel(level) { + var output = magicNumber + "&"; + output += level.height + "&" + level.width + "\n"; + + output += "?\n"; + for (var r = 0; r < level.height; r++) { + output += " " + level.map.slice(r * level.width, (r + 1) * level.width).join("") + "\n"; + } + output += "/\n"; + + output += serializeObjects(level.objects); + + // sanity check + var shouldBeTheSame = parseLevel(output); + if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken + + return output; +} +function serializeObjects(objects) { + var output = ""; + for (var i = 0; i < objects.length; i++) { + var object = objects[i]; + output += object.type + object.id + " "; + output += "?" + object.locations.join("&") + "/\n"; + } + return output; +} +function serializeObjectState(object) { + if (object == null) return [0,[]]; + return [object.dead, copyArray(object.locations)]; +} + +var base66 = "----0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +function compressSerialization(string) { + string = string.replace(/\s+/g, ""); + // run-length encode several 0's in a row, etc. + // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) + var result = ""; + var runStart = 0; + for (var i = 1; i < string.length + 1; i++) { + var runLength = i - runStart; + if (string[i] === string[runStart] && runLength < base66.length - 1) continue; + // end of run + if (runLength >= 4) { + // compress + result += "*" + base66[runLength] + string[runStart]; + } else { + // literal + result += string.substring(runStart, i); + } + runStart = i; + } + return result; +} +function decompressSerialization(string) { + string = string.replace(/\s+/g, ""); + var result = ""; + for (var i = 0; i < string.length; i++) { + if (string[i] === "*") { + i += 1; + var runLength = base66.indexOf(string[i]); + i += 1; + var char = string[i]; + for (var j = 0; j < runLength; j++) { + result += char; + } + } else { + result += string[i]; + } + } + return result; +} + +var replayMagicNumber = "nmGTi8PB"; +function stringifyReplay() { + var output = replayMagicNumber + "&"; + // only specify the snake id in an input if it's different from the previous. + // the first snake index is 0 to optimize for the single-snake case. + var currentSnakeId = 0; + for (var i = 0; i < unmoveStuff.undoStack.length; i++) { + var firstChange = unmoveStuff.undoStack[i][0]; + if (firstChange[0] !== "i") throw unreachable(); + var snakeId = firstChange[1]; + var dr = firstChange[2]; + var dc = firstChange[3]; + var directionCode; + if (dr ===-1 && dc === 0) directionCode = "u"; + else if (dr === 0 && dc ===-1) directionCode = "l"; + else if (dr === 1 && dc === 0) directionCode = "d"; + else if (dr === 0 && dc === 1) directionCode = "r"; + else throw unreachable(); + if (snakeId !== currentSnakeId) { + output += snakeId; // int to string + currentSnakeId = snakeId; + } + output += directionCode; + } + return output; +} +function parseAndLoadReplay(string) { + string = decompressSerialization(string); + var expectedPrefix = replayMagicNumber + "&"; + if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); + var cursor = expectedPrefix.length; + + // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. + activeSnakeId = 0; + while (cursor < string.length) { + var snakeIdStr = ""; + var c = string.charAt(cursor); + cursor += 1; + while ('0' <= c && c <= '9') { + snakeIdStr += c; + if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); + c = string.charAt(cursor); + cursor += 1; + } + if (snakeIdStr.length > 0) { + activeSnakeId = parseInt(snakeIdStr); + // don't just validate when switching snakes, but on every move. + } + + // doing a move. + if (!getSnakes().some(function(snake) { + return snake.id === activeSnakeId; + })) { + throw new Error("invalid snake id: " + activeSnakeId); + } + switch (c) { + case 'l': move( 0, -1); break; + case 'u': move(-1, 0); break; + case 'r': move( 0, 1); break; + case 'd': move( 1, 0); break; + default: throw new Error("replay string has invalid direction: " + c); + } + } + + // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. + reset(unmoveStuff); + document.getElementById("removeButton").classList.add("click-me"); +} + +var currentSerializedLevel; +function saveLevel() { + if (isDead()) return alert("Can't save while you're dead!"); + var serializedLevel = compressSerialization(stringifyLevel(level)); + currentSerializedLevel = serializedLevel; + var hash = "#level=" + serializedLevel; + expectHash = hash; + location.hash = hash; + + // This marks a starting point for solving the level. + unmoveStuff.undoStack = []; + unmoveStuff.redoStack = []; + editorHasBeenTouched = false; + undoStuffChanged(unmoveStuff); +} + +function saveReplay() { + if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); + // preserve the level in the url bar. + var hash = "#level=" + currentSerializedLevel; + if (dirtyState === REPLAY_DIRTY) { + // there is a replay to save + hash += "#replay=" + compressSerialization(stringifyReplay()); + } + expectHash = hash; + location.hash = hash; +} + +function deepEquals(a, b) { + if (a == null) return b == null; + if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; + if (Array.isArray(a)) { + if (!Array.isArray(b)) return false; + if (a.length !== b.length) return false; + for (var i = 0; i < a.length; i++) { + if (!deepEquals(a[i], b[i])) return false; + } + return true; + } + // must be objects + var aKeys = Object.keys(a); + var bKeys = Object.keys(b); + if (aKeys.length !== bKeys.length) return false; + aKeys.sort(); + bKeys.sort(); + if (!deepEquals(aKeys, bKeys)) return false; + for (var i = 0; i < aKeys.length; i++) { + if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; + } + return true; +} + +function getLocation(level, r, c) { + if (!isInBounds(level, r, c)) throw unreachable(); + return r * level.width + c; +} +function getRowcol(level, location) { + if (location < 0 || location >= level.width * level.height) throw unreachable(); + var r = Math.floor(location / level.width); + var c = location % level.width; + return {r:r, c:c}; +} +function isInBounds(level, r, c) { + if (c < 0 || c >= level.width) return false;; + if (r < 0 || r >= level.height) return false;; + return true; +} +function offsetLocation(location, dr, dc) { + var rowcol = getRowcol(level, location); + return getLocation(level, rowcol.r + dr, rowcol.c + dc); +} + +var SHIFT = 1; +var CTRL = 2; +var ALT = 4; +document.addEventListener("keydown", function(event) { + var modifierMask = ( + (event.shiftKey ? SHIFT : 0) | + (event.ctrlKey ? CTRL : 0) | + (event.altKey ? ALT : 0) + ); + switch (event.keyCode) { + case 37: // left + if (modifierMask === 0) { move(0, -1); break; } + return; + case 38: // up + if (modifierMask === 0) { move(-1, 0); break; } + return; + case 39: // right + if (modifierMask === 0) { move(0, 1); break; } + return; + case 40: // down + if (modifierMask === 0) { move(1, 0); break; } + return; + case 8: // backspace + if (modifierMask === 0) { undo(unmoveStuff); break; } + if (modifierMask === SHIFT) { redo(unmoveStuff); break; } + return; + case "Q".charCodeAt(0): + if (modifierMask === 0) { undo(unmoveStuff); break; } + if (modifierMask === SHIFT) { redo(unmoveStuff); break; } + return; + case "Z".charCodeAt(0): + if (modifierMask === 0) { undo(unmoveStuff); break; } + if (modifierMask === SHIFT) { redo(unmoveStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL) { undo(uneditStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL|SHIFT) { redo(uneditStuff); break; } + return; + case "Y".charCodeAt(0): + if (modifierMask === 0) { redo(unmoveStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL) { redo(uneditStuff); break; } + return; + case "R".charCodeAt(0): + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } + if (modifierMask === 0) { reset(unmoveStuff); break; } + if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } + return; + + case 220: // backslash + if (modifierMask === 0) { toggleShowEditor(); break; } + return; + case "A".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(0, -1); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PORTAL); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { selectAll(); break; } + return; + case "E".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } + return; + case 46: // delete + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } + return; + case "W".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } + return; + case "S".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPIKE); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { saveLevel(); break; } + if (!persistentState.showEditor && modifierMask === CTRL) { saveReplay(); break; } + if (modifierMask === (CTRL|SHIFT)) { saveReplay(); break; } + return; + case "X".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(EXIT); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } + return; + case "F".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } + return; + case "D".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SNAKE); break; } + return; + case "B".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } + return; + case "G".charCodeAt(0): + if (modifierMask === 0) { toggleGrid(); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } + return; + case "C".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === SHIFT) { toggleCollision(); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } + return; + case "V".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } + return; + case 32: // spacebar + case 9: // tab + if (modifierMask === 0) { switchSnakes( 1); break; } + if (modifierMask === SHIFT) { switchSnakes(-1); break; } + return; + case "1".charCodeAt(0): + case "2".charCodeAt(0): + case "3".charCodeAt(0): + case "4".charCodeAt(0): + var index = event.keyCode - "1".charCodeAt(0); + var delta; + if (modifierMask === 0) { + delta = 1; + } else if (modifierMask === SHIFT) { + delta = -1; + } else return; + if (isAlive()) { + (function() { + var snakes = findSnakesOfColor(index); + if (snakes.length === 0) return; + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) { + activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; + return; + } + } + activeSnakeId = snakes[0].id; + })(); + } + break; + case 27: // escape + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(null); break; } + return; + default: return; + } + event.preventDefault(); + render(); +}); + +document.getElementById("switchSnakesButton").addEventListener("click", function() { + switchSnakes(1); + render(); +}); +function switchSnakes(delta) { + if (!isAlive()) return; + var snakes = getSnakes(); + snakes.sort(compareId); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) { + activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; + return; + } + } + activeSnakeId = snakes[0].id; +} +document.getElementById("showGridButton").addEventListener("click", function() { + toggleGrid(); +}); +document.getElementById("saveProgressButton").addEventListener("click", function() { + saveReplay(); +}); +document.getElementById("restartButton").addEventListener("click", function() { + reset(unmoveStuff); + render(); +}); +document.getElementById("unmoveButton").addEventListener("click", function() { + undo(unmoveStuff); + render(); +}); +document.getElementById("removeButton").addEventListener("click", function() { + redo(unmoveStuff); + render(); +}); + +document.getElementById("showHideEditor").addEventListener("click", function() { + toggleShowEditor(); +}); +function toggleShowEditor() { + persistentState.showEditor = !persistentState.showEditor; + savePersistentState(); + showEditorChanged(); +} +function toggleGrid() { + persistentState.showGrid = !persistentState.showGrid; + savePersistentState(); + render(); +} +["serializationTextarea", "shareLinkTextbox"].forEach(function(id) { + document.getElementById(id).addEventListener("keydown", function(event) { + // let things work normally + event.stopPropagation(); + }); +}); +document.getElementById("submitSerializationButton").addEventListener("click", function() { + var string = document.getElementById("serializationTextarea").value; + try { + var newLevel = parseLevel(string); + } catch (e) { + alert(e); + return; + } + loadLevel(newLevel); +}); +document.getElementById("shareLinkTextbox").addEventListener("focus", function() { + setTimeout(function() { + document.getElementById("shareLinkTextbox").select(); + }, 0); +}); + +var paintBrushTileCode = null; +var paintBrushSnakeColorIndex = 0; +var paintBrushBlockId = 0; +var paintBrushObject = null; +var selectionStart = null; +var selectionEnd = null; +var resizeDragAnchorRowcol = null; +var clipboardData = null; +var clipboardOffsetRowcol = null; +var paintButtonIdAndTileCodes = [ + ["resizeButton", "resize"], + ["selectButton", "select"], + ["pasteButton", "paste"], + ["paintSpaceButton", SPACE], + ["paintWallButton", WALL], + ["paintSpikeButton", SPIKE], + ["paintExitButton", EXIT], + ["paintFruitButton", FRUIT], + ["paintPortalButton", PORTAL], + ["paintSnakeButton", SNAKE], + ["paintBlockButton", BLOCK], +]; +paintButtonIdAndTileCodes.forEach(function(pair) { + var id = pair[0]; + var tileCode = pair[1]; + document.getElementById(id).addEventListener("click", function() { + setPaintBrushTileCode(tileCode); + }); +}); +document.getElementById("uneditButton").addEventListener("click", function() { + undo(uneditStuff); + render(); +}); +document.getElementById("reeditButton").addEventListener("click", function() { + redo(uneditStuff); + render(); +}); +document.getElementById("saveLevelButton").addEventListener("click", function() { + saveLevel(); +}); +document.getElementById("copyButton").addEventListener("click", function() { + copySelection(); +}); +document.getElementById("cutButton").addEventListener("click", function() { + cutSelection(); +}); +document.getElementById("cheatGravityButton").addEventListener("click", function() { + toggleGravity(); +}); +document.getElementById("cheatCollisionButton").addEventListener("click", function() { + toggleCollision(); +}); +document.getElementById("backgroundButton").addEventListener("click", function() { + toggleBackground(); +}); +function toggleBackground() { + if(background == "sky") background = "gradient"; + else background = "sky"; +} +function toggleGravity() { + isGravityEnabled = !isGravityEnabled; + isCollisionEnabled = true; + refreshCheatButtonText(); +} +function toggleCollision() { + isCollisionEnabled = !isCollisionEnabled; + isGravityEnabled = false; + refreshCheatButtonText(); +} +function refreshCheatButtonText() { + document.getElementById("cheatGravityButton").textContent = isGravityEnabled ? "Gravity: ON" : "Gravity: OFF"; + document.getElementById("cheatGravityButton").style.background = isGravityEnabled ? "" : "#f88"; + + document.getElementById("cheatCollisionButton").textContent = isCollisionEnabled ? "Collision: ON" : "Collision: OFF"; + document.getElementById("cheatCollisionButton").style.background = isCollisionEnabled ? "" : "#f88"; +} + +// be careful with location vs rowcol, because this variable is used when resizing +var lastDraggingRowcol = null; +var hoverLocation = null; +var draggingChangeLog = null; +canvas.addEventListener("mousedown", function(event) { + if (event.altKey) return; + if (event.button !== 0) return; + event.preventDefault(); + var location = getLocationFromEvent(event); + if (persistentState.showEditor && paintBrushTileCode != null) { + // editor tool + lastDraggingRowcol = getRowcol(level, location); + if (paintBrushTileCode === "select") selectionStart = location; + if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; + draggingChangeLog = []; + paintAtLocation(location, draggingChangeLog); + } else { + // playtime + var object = findObjectAtLocation(location); + if (object == null) return; + if (object.type !== SNAKE) return; + // active snake + activeSnakeId = object.id; + render(); + } +}); +canvas.addEventListener("dblclick", function(event) { + if (event.altKey) return; + if (event.button !== 0) return; + event.preventDefault(); + if (persistentState.showEditor && paintBrushTileCode === "select") { + // double click with select tool + var location = getLocationFromEvent(event); + var object = findObjectAtLocation(location); + if (object == null) return; + stopDragging(); + if (object.type === SNAKE) { + // edit snakes of this color + paintBrushTileCode = SNAKE; + paintBrushSnakeColorIndex = object.id % snakeColors.length; + } else if (object.type === BLOCK) { + // edit this particular block + paintBrushTileCode = BLOCK; + paintBrushBlockId = object.id; + } else if (object.type === FRUIT) { + // edit fruits, i guess + paintBrushTileCode = FRUIT; + } else throw unreachable(); + paintBrushTileCodeChanged(); + } +}); +document.addEventListener("mouseup", function(event) { + stopDragging(); +}); +function stopDragging() { + if (lastDraggingRowcol != null) { + // release the draggin' + lastDraggingRowcol = null; + paintBrushObject = null; + resizeDragAnchorRowcol = null; + pushUndo(uneditStuff, draggingChangeLog); + draggingChangeLog = null; + } +} +canvas.addEventListener("mousemove", function(event) { + if (!persistentState.showEditor) return; + var location = getLocationFromEvent(event); + var mouseRowcol = getRowcol(level, location); + if (lastDraggingRowcol != null) { + // Dragging Force - Through the Fruit and Flames + var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); + // we need to get rowcols for everything before we start dragging, because dragging might resize the world. + var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function(location) { + return getRowcol(level, location); + }); + path.forEach(function(rowcol) { + // convert to location at the last minute in case each of these steps is changing the coordinate system. + paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); + }); + lastDraggingRowcol = mouseRowcol; + hoverLocation = null; + } else { + // hovering + if (hoverLocation !== location) { + hoverLocation = location; + render(); + } + } +}); +canvas.addEventListener("mouseout", function() { + if (hoverLocation !== location) { + // turn off the hover when the mouse leaves + hoverLocation = null; + render(); + } +}); +function getLocationFromEvent(event) { + var r = Math.floor(eventToMouseY(event, canvas) / tileSize); + var c = Math.floor(eventToMouseX(event, canvas) / tileSize); + // since the canvas is centered, the bounding client rect can be half-pixel aligned, + // resulting in slightly out-of-bounds mouse events. + r = clamp(r, 0, level.height); + c = clamp(c, 0, level.width); + return getLocation(level, r, c); +} +function eventToMouseX(event, canvas) { return event.clientX - canvas.getBoundingClientRect().left; } +function eventToMouseY(event, canvas) { return event.clientY - canvas.getBoundingClientRect().top; } + +function selectAll() { + selectionStart = 0; + selectionEnd = level.map.length - 1; + setPaintBrushTileCode("select"); +} + +function setPaintBrushTileCode(tileCode) { + if (tileCode === "paste") { + // make sure we have something to paste + if (clipboardData == null) return; + } + if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { + // usually this means to fill in the selection + if (tileCode == null) { + // cancel selection + selectionStart = null; + selectionEnd = null; + return; + } + if (typeof tileCode === "number" && tileCode !== PORTAL) { + // fill in the selection + fillSelection(tileCode); + selectionStart = null; + selectionEnd = null; + return; + } + // ok, just select something else then. + selectionStart = null; + selectionEnd = null; + } + if (tileCode === SNAKE) { + if (paintBrushTileCode === SNAKE) { + // next snake color + paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; + } + } else if (tileCode === BLOCK) { + var blocks = getBlocks(); + if (paintBrushTileCode === BLOCK && blocks.length > 0) { + // cycle through block ids + blocks.sort(compareId); + if (paintBrushBlockId != null) { + (function() { + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].id === paintBrushBlockId) { + i += 1; + if (i < blocks.length) { + // next block id + paintBrushBlockId = blocks[i].id; + } else { + // new block id + paintBrushBlockId = null; + } + return; + } + } + throw unreachable() + })(); + } else { + // first one + paintBrushBlockId = blocks[0].id; + } + } else { + // new block id + paintBrushBlockId = null; + } + } else if (tileCode == null) { + // escape + if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { + // stop editing this block, but keep the block brush selected + tileCode = BLOCK; + paintBrushBlockId = null; + } + } + paintBrushTileCode = tileCode; + paintBrushTileCodeChanged(); +} +function paintBrushTileCodeChanged() { + paintButtonIdAndTileCodes.forEach(function(pair) { + var id = pair[0]; + var tileCode = pair[1]; + var backgroundStyle = ""; + if (tileCode === paintBrushTileCode) { + if (tileCode === SNAKE) { + // show the color of the active snake in the color of the button + backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; + } else { + backgroundStyle = "#fdc122"; + } + } + document.getElementById(id).style.background = backgroundStyle; + }); + + var isSelectionMode = paintBrushTileCode === "select"; + ["cutButton", "copyButton"].forEach(function (id) { + document.getElementById(id).disabled = !isSelectionMode; + }); + document.getElementById("pasteButton").disabled = clipboardData == null; + + render(); +} + +function cutSelection() { + copySelection(); + fillSelection(SPACE); + render(); +} +function copySelection() { + var selectedLocations = getSelectedLocations(); + if (selectedLocations.length === 0) return; + var selectedObjects = []; + selectedLocations.forEach(function(location) { + var object = findObjectAtLocation(location); + if (object != null) addIfNotPresent(selectedObjects, object); + }); + setClipboardData({ + level: JSON.parse(JSON.stringify(level)), + selectedLocations: selectedLocations, + selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), + }); +} +function setClipboardData(data) { + // find the center + var minR = Infinity; + var maxR = -Infinity; + var minC = Infinity; + var maxC = -Infinity; + data.selectedLocations.forEach(function(location) { + var rowcol = getRowcol(data.level, location); + if (rowcol.r < minR) minR = rowcol.r; + if (rowcol.r > maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var offsetR = Math.floor((minR + maxR) / 2); + var offsetC = Math.floor((minC + maxC) / 2); + + clipboardData = data; + clipboardOffsetRowcol = {r:offsetR, c:offsetC}; + paintBrushTileCodeChanged(); +} +function fillSelection(tileCode) { + var changeLog = []; + var locations = getSelectedLocations(); + locations.forEach(function(location) { + if (level.map[location] !== tileCode) { + changeLog.push(["m", location, level.map[location], tileCode]); + level.map[location] = tileCode; + } + removeAnyObjectAtLocation(location, changeLog); + }); + pushUndo(uneditStuff, changeLog); +} +function getSelectedLocations() { + if (selectionStart == null || selectionEnd == null) return []; + var rowcol1 = getRowcol(level, selectionStart); + var rowcol2 = getRowcol(level, selectionEnd); + var r1 = rowcol1.r; + var c1 = rowcol1.c; + var r2 = rowcol2.r; + var c2 = rowcol2.c; + if (r2 < r1) { + var tmp = r1; + r1 = r2; + r2 = tmp; + } + if (c2 < c1) { + var tmp = c1; + c1 = c2; + c2 = tmp; + } + var objects = []; + var locations = []; + for (var r = r1; r <= r2; r++) { + for (var c = c1; c <= c2; c++) { + var location = getLocation(level, r, c); + locations.push(location); + var object = findObjectAtLocation(location); + if (object != null) addIfNotPresent(objects, object); + } + } + // select the rest of any partially-selected objects + objects.forEach(function(object) { + object.locations.forEach(function(location) { + addIfNotPresent(locations, location); + }); + }); + return locations; +} + +function setHeight(newHeight, changeLog) { + if (newHeight < level.height) { + // crop + for (var r = newHeight; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + removeAnyObjectAtLocation(location, changeLog); + // also delete non-space tiles + paintTileAtLocation(location, SPACE, changeLog); + } + } + level.map.splice(newHeight * level.width); + } else { + // expand + for (var r = level.height; r < newHeight; r++) { + for (var c = 0; c < level.width; c++) { + level.map.push(SPACE); + } + } + } + changeLog.push(["h", level.height, newHeight]); + level.height = newHeight; +} +function setWidth(newWidth, changeLog) { + if (newWidth < level.width) { + // crop + for (var r = level.height - 1; r >= 0; r--) { + for (var c = level.width - 1; c >= newWidth; c--) { + var location = getLocation(level, r, c); + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, SPACE, changeLog); + level.map.splice(location, 1); + } + } + } else { + // expand + for (var r = level.height - 1; r >= 0; r--) { + var insertionPoint = level.width * (r + 1); + for (var c = level.width; c < newWidth; c++) { + // boy is this inefficient. ... YOLO! + level.map.splice(insertionPoint, 0, SPACE); + } + } + } + + var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); + level.objects.forEach(function(object) { + object.locations = object.locations.map(transformLocation); + }); + + changeLog.push(["w", level.width, newWidth]); + level.width = newWidth; +} + +function newSnake(color, location) { + var snakes = findSnakesOfColor(color); + snakes.sort(compareId); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id !== i * snakeColors.length + color) break; + } + return { + type: SNAKE, + id: i * snakeColors.length + color, + dead: false, + locations: [location], + }; +} +function newBlock(location) { + var blocks = getBlocks(); + blocks.sort(compareId); + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].id !== i) break; + } + return { + type: BLOCK, + id: i, + dead: false, // unused + locations: [location], + }; +} +function newFruit(location) { + var fruits = getObjectsOfType(FRUIT); + fruits.sort(compareId); + for (var i = 0; i < fruits.length; i++) { + if (fruits[i].id !== i) break; + } + return { + type: FRUIT, + id: i, + dead: false, // unused + locations: [location], + }; +} +function paintAtLocation(location, changeLog) { + if (typeof paintBrushTileCode === "number") { + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, paintBrushTileCode, changeLog); + } else if (paintBrushTileCode === "resize") { + var toRowcol = getRowcol(level, location); + var dr = toRowcol.r - resizeDragAnchorRowcol.r; + var dc = toRowcol.c - resizeDragAnchorRowcol.c; + resizeDragAnchorRowcol = toRowcol; + if (dr !== 0) setHeight(level.height + dr, changeLog); + if (dc !== 0) setWidth(level.width + dc, changeLog); + } else if (paintBrushTileCode === "select") { + selectionEnd = location; + } else if (paintBrushTileCode === "paste") { + var hoverRowcol = getRowcol(level, location); + var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); + pastedData.selectedLocations.forEach(function(location) { + var tileCode = pastedData.level.map[location]; + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, tileCode, changeLog); + }); + pastedData.selectedObjects.forEach(function(object) { + // refresh the ids so there are no collisions. + if (object.type === SNAKE) { + object.id = newSnake(object.id % snakeColors.length).id; + } else if (object.type === BLOCK) { + object.id = newBlock().id; + } else if (object.type === FRUIT) { + object.id = newFruit().id; + } else throw unreachable(); + level.objects.push(object); + changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); + }); + } else if (paintBrushTileCode === SNAKE) { + var oldSnakeSerialization = serializeObjectState(paintBrushObject); + if (paintBrushObject != null) { + // keep dragging + if (paintBrushObject.locations[0] === location) return; // we just did that + // watch out for self-intersection + var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); + if (selfIntersectionIndex !== -1) { + // truncate from here back + paintBrushObject.locations.splice(selfIntersectionIndex); + } + } + + // make sure there's space behind us + paintTileAtLocation(location, SPACE, changeLog); + removeAnyObjectAtLocation(location, changeLog); + if (paintBrushObject == null) { + var thereWereNoSnakes = countSnakes() === 0; + paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); + level.objects.push(paintBrushObject); + if (thereWereNoSnakes) activateAnySnakePlease(); + } else { + // extend le snake + paintBrushObject.locations.unshift(location); + } + changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); + } else if (paintBrushTileCode === BLOCK) { + var objectHere = findObjectAtLocation(location); + if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { + // just start editing this block + paintBrushBlockId = objectHere.id; + } else { + // make a change + // make sure there's space behind us + paintTileAtLocation(location, SPACE, changeLog); + var thisBlock = null; + if (paintBrushBlockId != null) { + thisBlock = findBlockById(paintBrushBlockId); + } + var oldBlockSerialization = serializeObjectState(thisBlock); + if (thisBlock == null) { + // create new block + removeAnyObjectAtLocation(location, changeLog); + thisBlock = newBlock(location); + level.objects.push(thisBlock); + paintBrushBlockId = thisBlock.id; + } else { + var existingIndex = thisBlock.locations.indexOf(location); + if (existingIndex !== -1) { + // reclicking part of this object means to delete just part of it. + if (thisBlock.locations.length === 1) { + // goodbye + removeObject(thisBlock, changeLog); + paintBrushBlockId = null; + } else { + thisBlock.locations.splice(existingIndex, 1); + } + } else { + // add a tile to the block + removeAnyObjectAtLocation(location, changeLog); + thisBlock.locations.push(location); + } + } + changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); + delete blockSupportRenderCache[thisBlock.id]; + } + } else if (paintBrushTileCode === FRUIT) { + paintTileAtLocation(location, SPACE, changeLog); + removeAnyObjectAtLocation(location, changeLog); + var object = newFruit(location) + level.objects.push(object); + changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); + } else throw unreachable(); + render(); +} + +function paintTileAtLocation(location, tileCode, changeLog) { + if (level.map[location] === tileCode) return; + changeLog.push(["m", location, level.map[location], tileCode]); + level.map[location] = tileCode; +} + +function pushUndo(undoStuff, changeLog) { + // changeLog = [ + // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], + // // player input for snake 0, dr:-1, dc:0. has no effect on state. + // // "i" is always the first change in normal player movement. + // // if a changeLog does not start with "i", then it is an editor action. + // // animationQueue and freshlyRemovedAnimatedObjects + // // are used for animating re-move. + // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 + // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] + // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] + // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] + // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] + // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. + // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. + // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. + // 10, // the last change is always a declaration of the final width of the map. + // ]; + reduceChangeLog(changeLog); + if (changeLog.length === 0) return; + changeLog.push(level.width); + undoStuff.undoStack.push(changeLog); + undoStuff.redoStack = []; + paradoxes = []; + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; + + undoStuffChanged(undoStuff); +} +function reduceChangeLog(changeLog) { + for (var i = 0; i < changeLog.length - 1; i++) { + var change = changeLog[i]; + if (change[0] === "i") { + continue; // don't reduce player input + } else if (change[0] === "h") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "h") { + // combine + change[2] = otherChange[2]; + changeLog.splice(j, 1); + j--; + continue; + } else if (otherChange[0] === "w") { + continue; // no interaction between height and width + } else break; // no more reduction possible + } + if (change[1] === change[2]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === "w") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "w") { + // combine + change[2] = otherChange[2]; + changeLog.splice(j, 1); + j--; + continue; + } else if (otherChange[0] === "h") { + continue; // no interaction between height and width + } else break; // no more reduction possible + } + if (change[1] === change[2]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === "m") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "m" && otherChange[1] === change[1]) { + // combine + change[3] = otherChange[3]; + changeLog.splice(j, 1); + j--; + } else if (otherChange[0] === "w" || otherChange[0] === "h") { + break; // can't reduce accros resizes + } + } + if (change[2] === change[3]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === change[0] && otherChange[1] === change[1]) { + // combine + change[3] = otherChange[3]; + changeLog.splice(j, 1); + j--; + } else if (otherChange[0] === "w" || otherChange[0] === "h") { + break; // can't reduce accros resizes + } + } + if (deepEquals(change[2], change[3])) { + // no change + changeLog.splice(i, 1); + i--; + } + } else throw unreachable(); + } +} +function undo(undoStuff) { + if (undoStuff.undoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + undoOneFrame(undoStuff); + undoStuffChanged(undoStuff); +} +function reset(undoStuff) { + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + while (undoStuff.undoStack.length > 0) { + undoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); +} +function undoOneFrame(undoStuff) { + var doThis = undoStuff.undoStack.pop(); + var redoChangeLog = []; + undoChanges(doThis, redoChangeLog); + if (redoChangeLog.length > 0) { + redoChangeLog.push(level.width); + undoStuff.redoStack.push(redoChangeLog); + } + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; +} +function redo(undoStuff) { + if (undoStuff.redoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + redoOneFrame(undoStuff); + undoStuffChanged(undoStuff); +} +function unreset(undoStuff) { + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + while (undoStuff.redoStack.length > 0) { + redoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); + + // don't animate the last frame + animationQueue = []; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = []; +} +function redoOneFrame(undoStuff) { + var doThis = undoStuff.redoStack.pop(); + var undoChangeLog = []; + undoChanges(doThis, undoChangeLog); + if (undoChangeLog.length > 0) { + undoChangeLog.push(level.width); + undoStuff.undoStack.push(undoChangeLog); + } + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; +} +function undoChanges(changes, changeLog) { + var widthContext = changes.pop(); + var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); + for (var i = changes.length - 1; i >= 0; i--) { + var paradoxDescription = undoChange(changes[i]); + if (paradoxDescription != null) paradoxes.push(paradoxDescription); + } + + var lastChange = changes[changes.length - 1]; + if (lastChange[0] === "i") { + // replay animation + animationQueue = lastChange[4]; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = lastChange[5]; + animationStart = new Date().getTime(); + } + + function undoChange(change) { + // note: everything here is going backwards: to -> from + if (change[0] === "i") { + // no state change, but preserve the intention. + changeLog.push(change); + return null; + } else if (change[0] === "h") { + // change height + var fromHeight = change[1]; + var toHeight = change[2]; + if (level.height !== toHeight) return "Impossible"; + setHeight(fromHeight, changeLog); + } else if (change[0] === "w") { + // change width + var fromWidth = change[1]; + var toWidth = change[2]; + if (level.width !== toWidth) return "Impossible"; + setWidth(fromWidth, changeLog); + } else if (change[0] === "m") { + // change map tile + var location = transformLocation(change[1]); + var fromTileCode = change[2]; + var toTileCode = change[3]; + if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; + if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; + paintTileAtLocation(location, fromTileCode, changeLog); + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { + // change object + var type = change[0]; + var id = change[1]; + var fromDead = change[2][0]; + var toDead = change[3][0]; + var fromLocations = change[2][1].map(transformLocation); + var toLocations = change[3][1].map(transformLocation); + if (fromLocations.filter(function(location) { return location >= level.map.length; }).length > 0) { + return "Can't move " + describe(type, id) + " out of bounds"; + } + var object = findObjectOfTypeAndId(type, id); + if (toLocations.length !== 0) { + // should exist at this location + if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; + if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; + if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; + // doit + if (fromLocations.length !== 0) { + var oldState = serializeObjectState(object); + object.locations = fromLocations; + object.dead = fromDead; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + } else { + removeObject(object, changeLog); + } + } else { + // shouldn't exist + if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; + // doit + object = { + type: type, + id: id, + dead: fromDead, + locations: fromLocations, + }; + level.objects.push(object); + changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); + } + } else throw unreachable(); + } +} +function describe(arg1, arg2) { + // describe(0) -> "Space" + // describe(SNAKE, 0) -> "Snake 0 (Red)" + // describe(object) -> "Snake 0 (Red)" + // describe(BLOCK, 1) -> "Block 1" + // describe(FRUIT) -> "Fruit" + if (typeof arg1 === "number") { + switch (arg1) { + case SPACE: return "Space"; + case WALL: return "a Wall"; + case SPIKE: return "Spikes"; + case EXIT: return "an Exit"; + case PORTAL: return "a Portal"; + default: throw unreachable(); + } + } + if (arg1 === SNAKE) { + var color = (function() { + switch (snakeColors[arg2 % snakeColors.length]) { + case "#fd0c0b": return " (Red)"; + case "#18d11f": return " (Green)"; + case "#004cff": return " (Blue)"; + case "#fdc122": return " (Yellow)"; + default: throw unreachable(); + } + })(); + return "Snake " + arg2 + color; + } + if (arg1 === BLOCK) { + return "Block " + arg2; + } + if (arg1 === FRUIT) { + return "Fruit"; + } + if (typeof arg1 === "object") return describe(arg1.type, arg1.id); + throw unreachable(); +} + +function undoStuffChanged(undoStuff) { + var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; + document.getElementById(undoStuff.spanId).textContent = movesText; + document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; + document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; + + // render paradox display + var uniqueParadoxes = []; + var paradoxCounts = []; + paradoxes.forEach(function(paradoxDescription) { + var index = uniqueParadoxes.indexOf(paradoxDescription); + if (index !== -1) { + paradoxCounts[index] += 1; + } else { + uniqueParadoxes.push(paradoxDescription); + paradoxCounts.push(1); + } + }); + var paradoxDivContent = ""; + uniqueParadoxes.forEach(function(paradox, i) { + if (i > 0) paradoxDivContent += "
\n"; + if (paradoxCounts[i] > 1) paradoxDivContent += "(" + paradoxCounts[i] + "x) "; + paradoxDivContent += "Time Travel Paradox! " + uniqueParadoxes[i]; + }); + document.getElementById("paradoxDiv").innerHTML = paradoxDivContent; + + updateDirtyState(); + + if (unmoveStuff.redoStack.length === 0) { + document.getElementById("removeButton").classList.remove("click-me"); + } +} + +var CLEAN_NO_TIMELINES = 0; +var CLEAN_WITH_REDO = 1; +var REPLAY_DIRTY = 2; +var EDITOR_DIRTY = 3; +var dirtyState = CLEAN_NO_TIMELINES; +var editorHasBeenTouched = false; +function updateDirtyState() { + if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { + dirtyState = EDITOR_DIRTY; + } else if (unmoveStuff.undoStack.length > 0) { + dirtyState = REPLAY_DIRTY; + } else if (unmoveStuff.redoStack.length > 0) { + dirtyState = CLEAN_WITH_REDO; + } else { + dirtyState = CLEAN_NO_TIMELINES; + } + + var saveLevelButton = document.getElementById("saveLevelButton"); + // the save button clears your timelines + saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; + if (dirtyState >= EDITOR_DIRTY) { + // you should save + saveLevelButton.classList.add("click-me"); + saveLevelButton.textContent = "*" + "Save Level"; + } else { + saveLevelButton.classList.remove("click-me"); + saveLevelButton.textContent = "Save Level"; + } + + var saveProgressButton = document.getElementById("saveProgressButton"); + // you can't save a replay if your level is dirty + if (dirtyState === CLEAN_WITH_REDO) { + saveProgressButton.textContent = "Forget Progress"; + } else { + saveProgressButton.textContent = "Save Progress"; + } + saveProgressButton.disabled = dirtyState >= EDITOR_DIRTY || dirtyState === CLEAN_NO_TIMELINES; +} +function haveCheatcodesBeenUsed() { + return !unmoveStuff.undoStack.every(function(changeLog) { + // normal movement always starts with "i". + return changeLog[0][0] === "i"; + }); +} + +var persistentState = { + showEditor: false, + showGrid: false, +}; +function savePersistentState() { + localStorage.snakefall = JSON.stringify(persistentState); +} +function loadPersistentState() { + try { + persistentState = JSON.parse(localStorage.snakefall); + } catch (e) { + } + persistentState.showEditor = !!persistentState.showEditor; + persistentState.showGrid = !!persistentState.showGrid; + showEditorChanged(); +} +var isGravityEnabled = true; +function isGravity() { + return isGravityEnabled || !persistentState.showEditor; +} +var isCollisionEnabled = true; +function isCollision() { + return isCollisionEnabled || !persistentState.showEditor; +} +function isAnyCheatcodeEnabled() { + return persistentState.showEditor && ( + !isGravityEnabled || !isCollisionEnabled + ); +} +var background = [ + "sky", + "gradient", +]; + + +function showEditorChanged() { + document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor Stuff"; + ["editorDiv", "editorPane"].forEach(function(id) { + document.getElementById(id).style.display = persistentState.showEditor ? "block" : "none"; + }); + document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : "/WASD"; + + render(); +} + +function move(dr, dc) { + if (!isAlive()) return; + animationQueue = []; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = []; + animationStart = new Date().getTime(); + var activeSnake = findActiveSnake(); + var headRowcol = getRowcol(level, activeSnake.locations[0]); + var newRowcol = {r:headRowcol.r + dr, c:headRowcol.c + dc}; + if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; + var newLocation = getLocation(level, newRowcol.r, newRowcol.c); + var changeLog = []; + + // The changeLog for a player movement starts with the input + // when playing normally. + if (!isAnyCheatcodeEnabled()) { + changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); + } + + var ate = false; + var pushedObjects = []; + + if (isCollision()) { + var newTile = level.map[newLocation]; + if (!isTileCodeAir(newTile)) return; // can't go through that tile + var otherObject = findObjectAtLocation(newLocation); + if (otherObject != null) { + if (otherObject === activeSnake) return; // can't push yourself + if (otherObject.type === FRUIT) { + // eat + removeObject(otherObject, changeLog); + ate = true; + } else { + // push objects + if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; + } + } + } + + // slither forward + var activeSnakeOldState = serializeObjectState(activeSnake); + var size1 = activeSnake.locations.length === 1; + var slitherAnimations = [ + 70, + [ + // size-1 snakes really do more of a move than a slither + size1 ? MOVE_SNAKE : SLITHER_HEAD, + activeSnake.id, + dr, + dc, + ] + ]; + activeSnake.locations.unshift(newLocation); + if (!ate) { + // drag your tail forward + var oldRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 1]); + var newRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 2]); + if (!size1) { + slitherAnimations.push([ + SLITHER_TAIL, + activeSnake.id, + newRowcol.r - oldRowcol.r, + newRowcol.c - oldRowcol.c, + ]); + } + activeSnake.locations.pop(); + } + changeLog.push([activeSnake.type, activeSnake.id, activeSnakeOldState, serializeObjectState(activeSnake)]); + + // did you just push your face into a portal? + var portalLocations = getActivePortalLocations(); + var portalActivationLocations = []; + if (portalLocations.indexOf(newLocation) !== -1) { + portalActivationLocations.push(newLocation); + } + // push everything, too + moveObjects(pushedObjects, dr, dc, portalLocations, portalActivationLocations, changeLog, slitherAnimations); + animationQueue.push(slitherAnimations); + + // gravity loop + var stateToAnimationIndex = {}; + if (isGravity()) for (var fallHeight = 1;; fallHeight++) { + var serializedState = serializeObjects(level.objects); + var infiniteLoopStartIndex = stateToAnimationIndex[serializedState]; + if (infiniteLoopStartIndex != null) { + // infinite loop + animationQueue.push([0, [INFINITE_LOOP, animationQueue.length - infiniteLoopStartIndex]]); + break; + } else { + stateToAnimationIndex[serializedState] = animationQueue.length; + } + // do portals separate from falling logic + if (portalActivationLocations.length === 1) { + var portalAnimations = [500]; + if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { + animationQueue.push(portalAnimations); + } + portalActivationLocations = []; + } + // now do falling logic + var didAnything = false; + var fallingAnimations = [ + 70 / Math.sqrt(fallHeight), + ]; + var exitAnimationQueue = []; + + // check for exit + if (!isUneatenFruit()) { //Gooby + var snakes = getSnakes(); + for (var i = 0; i < snakes.length; i++) { + var snake = snakes[i]; + if (level.map[snake.locations[0]] === EXIT) { + // (one of) you made it! + removeAnimatedObject(snake, changeLog); + exitAnimationQueue.push([ + 200, + [EXIT_SNAKE, snake.id, 0, 0], + ]); + didAnything = true; + } + } + } + + // fall + var dyingObjects = []; + var fallingObjects = level.objects.filter(function(object) { + if (object.type === FRUIT) return; // can't fall + var theseDyingObjects = []; + if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; + // this object can fall. maybe more will fall with it too. we'll check those separately. + theseDyingObjects.forEach(function(object) { + addIfNotPresent(dyingObjects, object); + }); + return true; + }); + if (dyingObjects.length > 0) { + var anySnakesDied = false; + dyingObjects.forEach(function(object) { + if (object.type === SNAKE) { + // look what you've done + var oldState = serializeObjectState(object); + object.dead = true; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + anySnakesDied = true; + } else if (object.type === BLOCK) { + // a box fell off the world + removeAnimatedObject(object, changeLog); + removeFromArray(fallingObjects, object); + exitAnimationQueue.push([ + 200, + [ + DIE_BLOCK, + object.id, + 0, 0 + ], + ]); + didAnything = true; + } else throw unreachable(); + }); + if (anySnakesDied) break; + } + if (fallingObjects.length > 0) { + moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); + didAnything = true; + } + + if (!didAnything) break; + Array.prototype.push.apply(animationQueue, exitAnimationQueue); + if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); + } + + pushUndo(unmoveStuff, changeLog); + render(); +} + +function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects) { + // pusher can be null (for gravity) + pushedObjects.push(pushedObject); + // find forward locations + var forwardLocations = []; + for (var i = 0; i < pushedObjects.length; i++) { + pushedObject = pushedObjects[i]; + for (var j = 0; j < pushedObject.locations.length; j++) { + var rowcol = getRowcol(level, pushedObject.locations[j]); + var forwardRowcol = {r:rowcol.r + dr, c:rowcol.c + dc}; + if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { + if (dyingObjects == null) { + // can't push things out of bounds + return false; + } else { + // this thing is going to fall out of bounds + addIfNotPresent(dyingObjects, pushedObject); + addIfNotPresent(pushedObjects, pushedObject); + continue; + } + } + var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); + var yetAnotherObject = findObjectAtLocation(forwardLocation); + if (yetAnotherObject != null) { + if (yetAnotherObject.type === FRUIT) { + // not pushable + return false; + } + if (yetAnotherObject === pusher) { + // indirect pushing ourselves. + // special check for when we're indirectly pushing the tip of our own tail. + if (forwardLocation === pusher.locations[pusher.locations.length -1]) { + // for some reason this is ok. + continue; + } + return false; + } + addIfNotPresent(pushedObjects, yetAnotherObject); + } else { + addIfNotPresent(forwardLocations, forwardLocation); + } + } + } + // check forward locations + for (var i = 0; i < forwardLocations.length; i++) { + var forwardLocation = forwardLocations[i]; + // many of these locations can be inside objects, + // but that means the tile must be air, + // and we already know pushing that object. + var tileCode = level.map[forwardLocation]; + if (!isTileCodeAir(tileCode)) { + if (dyingObjects != null) { + if (tileCode === SPIKE) { + // uh... which object was this again? + var deadObject = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); + if (deadObject.type === SNAKE) { + // ouch! + addIfNotPresent(dyingObjects, deadObject); + continue; + } + } + } + // can't push into something solid + return false; + } + } + // the push is go + return true; +} + +function activateAnySnakePlease() { + var snakes = getSnakes(); + if (snakes.length === 0) return; // nope.avi + activeSnakeId = snakes[0].id; +} + +function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations, changeLog, animations) { + objects.forEach(function(object) { + var oldState = serializeObjectState(object); + var oldPortals = getSetIntersection(portalLocations, object.locations); + for (var i = 0; i < object.locations.length; i++) { + object.locations[i] = offsetLocation(object.locations[i], dr, dc); + } + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + animations.push([ + "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK + object.id, + dr, + dc, + ]); + + var newPortals = getSetIntersection(portalLocations, object.locations); + var activatingPortals = newPortals.filter(function(portalLocation) { + return oldPortals.indexOf(portalLocation) === -1; + }); + if (activatingPortals.length === 1) { + // exactly one new portal we're touching. activate it + portalActivationLocations.push(activatingPortals[0]); + } + }); +} + +function activatePortal(portalLocations, portalLocation, animations, changeLog) { + var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; + var portalRowcol = getRowcol(level, portalLocation); + var otherPortalRowcol = getRowcol(level, otherPortalLocation); + var delta = {r:otherPortalRowcol.r - portalRowcol.r, c:otherPortalRowcol.c - portalRowcol.c}; + + var object = findObjectAtLocation(portalLocation); + var newLocations = []; + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r + delta.r; + var c = rowcol.c + delta.c; + if (!isInBounds(level, r, c)) return false; // out of bounds + newLocations.push(getLocation(level, r, c)); + } + + for (var i = 0; i < newLocations.length; i++) { + var location = newLocations[i]; + if (!isTileCodeAir(level.map[location])) return false; // blocked by tile + var otherObject = findObjectAtLocation(location); + if (otherObject != null && otherObject !== object) return false; // blocked by object + } + + // zappo presto! + var oldState = serializeObjectState(object); + object.locations = newLocations; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + animations.push([ + "t" + object.type, // TELEPORT_SNAKE | TELEPORT_BLOCK + object.id, + delta.r, + delta.c, + ]); + return true; +} + +function isTileCodeAir(tileCode) { + return tileCode === SPACE || tileCode === EXIT || tileCode === PORTAL; +} + +function addIfNotPresent(array, element) { + if (array.indexOf(element) !== -1) return; + array.push(element); +} +function removeAnyObjectAtLocation(location, changeLog) { + var object = findObjectAtLocation(location); + if (object != null) removeObject(object, changeLog); +} +function removeAnimatedObject(object, changeLog) { + removeObject(object, changeLog); + freshlyRemovedAnimatedObjects.push(object); +} +function removeObject(object, changeLog) { + removeFromArray(level.objects, object); + changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0,[]]]); + if (object.type === SNAKE && object.id === activeSnakeId) { + activateAnySnakePlease(); + } + if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { + // no longer editing an object that doesn't exit + paintBrushBlockId = null; + } + if (object.type === BLOCK) { + delete blockSupportRenderCache[object.id]; + } +} +function removeFromArray(array, element) { + var index = array.indexOf(element); + if (index === -1) throw unreachable(); + array.splice(index, 1); +} +function findActiveSnake() { + var snakes = getSnakes(); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) return snakes[i]; + } + throw unreachable(); +} +function findBlockById(id) { + return findObjectOfTypeAndId(BLOCK, id); +} +function findSnakesOfColor(color) { + return level.objects.filter(function(object) { + if (object.type !== SNAKE) return false; + return object.id % snakeColors.length === color; + }); +} +function findObjectOfTypeAndId(type, id) { + for (var i = 0; i < level.objects.length; i++) { + var object = level.objects[i]; + if (object.type === type && object.id === id) return object; + } + return null; +} +function findObjectAtLocation(location) { + for (var i = 0; i < level.objects.length; i++) { + var object = level.objects[i]; + if (object.locations.indexOf(location) !== -1) + return object; + } + return null; +} +function isUneatenFruit() { + return getObjectsOfType(FRUIT).length > 0; +} +function getActivePortalLocations() { + var portalLocations = getPortalLocations(); + if (portalLocations.length !== 2) return []; // nice try + return portalLocations; +} +function getPortalLocations() { + var result = []; + for (var i = 0; i < level.map.length; i++) { + if (level.map[i] === PORTAL) result.push(i); + } + return result; +} +function countSnakes() { + return getSnakes().length; +} +function getSnakes() { + return getObjectsOfType(SNAKE); +} +function getBlocks() { + return getObjectsOfType(BLOCK); +} +function getObjectsOfType(type) { + return level.objects.filter(function(object) { + return object.type == type; + }); +} +function isDead() { + if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; + return getSnakes().filter(function(snake) { + return !!snake.dead; + }).length > 0; +} +function isAlive() { + return countSnakes() > 0 && !isDead(); +} + +var snakeColors = [ + "#fd0c0b", + "#18d11f", + "#004cff", + "#fdc122", +]; +var snakeAltColors = [ + "#ff6666", + "#66ff66", + "#6666ff", + "#ffff66", +]; +var blockForeground = ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"]; +var blockBackground = ["#853641","#963c84","#753d88","#5d3a96","#3a3990"]; + +var activeSnakeId = null; + +var SLITHER_HEAD = "sh"; +var SLITHER_TAIL = "st"; +var MOVE_SNAKE = "ms"; +var MOVE_BLOCK = "mb"; +var TELEPORT_SNAKE = "ts"; +var TELEPORT_BLOCK = "tb"; +var EXIT_SNAKE = "es"; +var DIE_SNAKE = "ds"; +var DIE_BLOCK = "db"; +var INFINITE_LOOP = "il"; +var animationQueue = [ + // // sequence of disjoint animation groups. + // // each group completes before the next begins. + // [ + // 70, // duration of this animation group + // // multiple things to animate simultaneously + // [ + // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, + // objectId, + // dr, + // dc, + // ], + // [ + // INFINITE_LOOP, + // loopSizeNotIncludingThis, + // ], + // ], +]; +var animationQueueCursor = 0; +var animationStart = null; // new Date().getTime() +var animationProgress; // 0.0 <= x < 1.0 +var freshlyRemovedAnimatedObjects = []; + +// render the support beams for blocks into a temporary buffer, and remember it. +// this is due to stencil buffers causing slowdown on some platforms. see #25. +var blockSupportRenderCache = { + // id: canvas, + // "0": document.createElement("canvas"), +}; + +function render() { + if (level == null) return; + if (animationQueueCursor < animationQueue.length) { + var animationDuration = animationQueue[animationQueueCursor][0]; + animationProgress = (new Date().getTime() - animationStart) / animationDuration; + if (animationProgress >= 1.0) { + // animation group complete + animationProgress -= 1.0; + animationQueueCursor++; + if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { + var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; + animationQueueCursor -= infiniteLoopSize; + } + animationStart = new Date().getTime(); + } + } + if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; + canvas.width = tileSize * level.width; + canvas.height = tileSize * level.height; + var context = canvas.getContext("2d"); //Gooby + + if(background=="gradient"){ + for(var i = 0; i maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var image = blockSupportRenderCache[object.id]; + if (image == null) { + // render the support beams to a buffer + blockSupportRenderCache[object.id] = image = document.createElement("canvas"); + image.width = (maxC - minC + 1) * tileSize; + image.height = (maxR - minR + 1) * tileSize; + var bufferContext = image.getContext("2d"); + // Make a stencil that excludes the insides of blocks. + // Then when we render the support beams, we won't see the supports inside the block itself. + bufferContext.beginPath(); + // Draw a path around the whole screen in the opposite direction as the rectangle paths below. + // This means that the below rectangles will be removing area from the greater rectangle. + bufferContext.rect(image.width, 0, -image.width, image.height); + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r - minR; + var c = rowcol.c - minC; + bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); + } + bufferContext.clip(); + for (var i = 0; i < object.locations.length - 1; i++) { + var rowcol1 = getRowcol(level, object.locations[i]); + rowcol1.r -= minR; + rowcol1.c -= minC; + var rowcol2 = getRowcol(level, object.locations[i + 1]); + rowcol2.r -= minR; + rowcol2.c -= minC; + var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; + drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockBackground[object.id % blockBackground.length]); + drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockBackground[object.id % blockBackground.length]); + } + } + var r = minR + animationDisplacementRowcol.r; + var c = minC + animationDisplacementRowcol.c; + context.drawImage(image, c * tileSize, r * tileSize); + }); + + // terrain + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + var tileCode = level.map[location]; + drawTile(tileCode, r, c, level, location); + } + } + } + + // objects + objects.forEach(drawObject); + + // banners + if (countSnakes() === 0) { + context.fillStyle = "#fdc122"; + context.font = "150px Impact"; + context.shadowOffsetX = 5; + context.shadowOffsetY = 5; + context.shadowColor = "rgba(0,0,0,0.5)"; + context.shadowBlur = 4; + var textString = "WIN"; + var textWidth = context.measureText(textString).width; + context.fillText(textString, (canvas.width/2) - (textWidth/2), canvas.height/2); + } + if (isDead()) { + context.fillStyle = "#fd0c0b"; + context.font = "150px Impact"; + context.shadowOffsetX = 5; + context.shadowOffsetY = 5; + context.shadowColor = "rgba(0,0,0,0.5)"; + context.shadowBlur = 4; + textString = "LOSE"; + textWidth = context.measureText(textString).width; + context.fillText(textString, (canvas.width/2) - (textWidth/2), canvas.height/2); + } + + // editor hover + if (persistentState.showEditor && paintBrushTileCode != null && hoverLocation != null && hoverLocation < level.map.length) { + + var savedContext = context; + var buffer = document.createElement("canvas"); + buffer.width = canvas.width; + buffer.height = canvas.height; + context = buffer.getContext("2d"); + + var hoverRowcol = getRowcol(level, hoverLocation); + var objectHere = findObjectAtLocation(hoverLocation); + if (typeof paintBrushTileCode === "number") { + if (level.map[hoverLocation] !== paintBrushTileCode) { + drawTile(paintBrushTileCode, hoverRowcol.r, hoverRowcol.c, level, hoverLocation); + } + } else if (paintBrushTileCode === SNAKE) { + if (!(objectHere != null && objectHere.type === SNAKE && objectHere.id === paintBrushSnakeColorIndex)) { + drawObject(newSnake(paintBrushSnakeColorIndex, hoverLocation)); + } + } else if (paintBrushTileCode === BLOCK) { + if (!(objectHere != null && objectHere.type === BLOCK && objectHere.id === paintBrushBlockId)) { + drawObject(newBlock(hoverLocation)); + } + } else if (paintBrushTileCode === FRUIT) { + if (!(objectHere != null && objectHere.type === FRUIT)) { + drawObject(newFruit(hoverLocation)); + } + } else if (paintBrushTileCode === "resize") { + void 0; // do nothing + } else if (paintBrushTileCode === "select") { + void 0; // do nothing + } else if (paintBrushTileCode === "paste") { + // show what will be pasted if you click + var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); + pastedData.selectedLocations.forEach(function(location) { + var tileCode = pastedData.level.map[location]; + var rowcol = getRowcol(level, location); + drawTile(tileCode, rowcol.r, rowcol.c, pastedData.level, location); + }); + pastedData.selectedObjects.forEach(drawObject); + } else throw unreachable(); + + context = savedContext; + context.save(); + context.globalAlpha = 0.2; + context.drawImage(buffer, 0, 0); + context.restore(); + } + } + function drawTile(tileCode, r, c, level, location) { + switch (tileCode) { + case SPACE: + break; + case WALL: + drawWall(r, c, getAdjacentTiles()); + break; + case SPIKE: + drawSpikes(r, c, getAdjacentTiles(), level); + break; + case EXIT: + drawExit(r, c); + /*var radiusFactor = isUneatenFruit() ? 0.7 : 1.2; + drawQuarterPie(r, c, radiusFactor, "#fd0c0b", 0); + drawQuarterPie(r, c, radiusFactor, "#18d11f", 1); + drawQuarterPie(r, c, radiusFactor, "#004cff", 2); + drawQuarterPie(r, c, radiusFactor, "#fdc122", 3);*/ + break; + case PORTAL: + drawCircle(r, c, 0.8, "#888"); + drawCircle(r, c, 0.6, "#111"); + if (activePortalLocations.indexOf(location) !== -1) drawCircle(r, c, 0.3, "#666"); + break; + default: throw unreachable(); + } + function getAdjacentTiles() { + return [ + [getTile(r - 1, c - 1), + getTile(r - 1, c + 0), + getTile(r - 1, c + 1)], + [getTile(r + 0, c - 1), + null, + getTile(r + 0, c + 1)], + [getTile(r + 1, c - 1), + getTile(r + 1, c + 0), + getTile(r + 1, c + 1)], + ]; + } + function getTile(r, c) { + if (!isInBounds(level, r, c)) return null; + return level.map[getLocation(level, r, c)]; + } + } + + function drawObject(object) { + switch (object.type) { + case SNAKE: + var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); + var lastRowcol = null + var color = snakeColors[object.id % snakeColors.length]; + //var altColor = snakeAltColors[object.id % snakeAltColors.length]; + var headRowcol; + for (var i = 0; i <= object.locations.length; i++) { + var animation; + var rowcol; + if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { + // animate head slithering forward + rowcol = getRowcol(level, object.locations[i]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else if (i === object.locations.length) { + // animated tail? + if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { + // animate tail slithering to catch up + rowcol = getRowcol(level, object.locations[i - 1]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else { + // no animated tail needed + break; + } + } else { + rowcol = getRowcol(level, object.locations[i]); + } + if (object.dead) rowcol.r += 0.5; + rowcol.r += animationDisplacementRowcol.r; + rowcol.c += animationDisplacementRowcol.c; + if (i === 0) { + // head + headRowcol = rowcol; + drawDiamond(rowcol.r, rowcol.c, color); + } else { + // middle + var cx = (rowcol.c + 0.5) * tileSize; + var cy = (rowcol.r + 0.5) * tileSize; + /*if(i % 2 == 0)*/ context.fillStyle = color; + //else context.fillStyle = altColor; + var orientation; + if (lastRowcol.r < rowcol.r) { + orientation = 0; + context.beginPath(); + context.moveTo((lastRowcol.c + 0) * tileSize, (lastRowcol.r + 0.5) * tileSize); + context.lineTo((lastRowcol.c + 1) * tileSize, (lastRowcol.r + 0.5) * tileSize); + context.arc(cx, cy, tileSize/2, 0, Math.PI); + context.fill(); + } else if (lastRowcol.r > rowcol.r) { + orientation = 2; + context.beginPath(); + context.moveTo((lastRowcol.c + 1) * tileSize, (lastRowcol.r + 0.5) * tileSize); + context.lineTo((lastRowcol.c + 0) * tileSize, (lastRowcol.r + 0.5) * tileSize); + context.arc(cx, cy, tileSize/2, Math.PI, 0); + context.fill(); + } else if (lastRowcol.c < rowcol.c) { + orientation = 3; + context.beginPath(); + context.moveTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 1) * tileSize); + context.lineTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 0) * tileSize); + context.arc(cx, cy, tileSize/2, 1.5 * Math.PI, 2.5 * Math.PI); + context.fill(); + } else if (lastRowcol.c > rowcol.c) { + orientation = 1; + context.beginPath(); + context.moveTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 0) * tileSize); + context.lineTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 1) * tileSize); + context.arc(cx, cy, tileSize/2, 2.5 * Math.PI, 1.5 * Math.PI); + context.fill(); + } + } + lastRowcol = rowcol; + } + // eye + if (object.id === activeSnakeId) { + drawCircle(headRowcol.r, headRowcol.c, 0.5, "#fff"); + drawCircle(headRowcol.r, headRowcol.c, 0.2, "#000"); + } + break; + case BLOCK: + drawBlock(object); + break; + case FRUIT: + var rowcol = getRowcol(level, object.locations[0]); + //drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); + + context.drawImage(img3,rowcol.c*tileSize+(tileSize*.1), rowcol.r*tileSize+(tileSize*.1), tileSize*.8, tileSize*.8); + break; + default: throw unreachable(); + } + } + + function drawExit(r, c) { //Gooby + /*var cx = c+.5; + var rx = r+.5; + + var grd = context.createRadialGradient(cx*tileSize, rx*tileSize, 1, cx*tileSize, rx*tileSize, 13); + grd.addColorStop(1, "red"); + grd.addColorStop(.8, "orange"); + grd.addColorStop(.6, "yellow"); + grd.addColorStop(.4, "green"); + grd.addColorStop(.2, "blue"); + grd.addColorStop(0, "violet"); + context.fillStyle = grd; + + context.arc(cx*tileSize,rx*tileSize,tileSize/2,0,2*Math.PI); + context.fill(); + context.stroke();*/ + + var img2=document.createElement('img'); + img2.src='/Snakefall/Snakebird Images/pinwheel.png'; + + if(isUneatenFruit()==0) + context.drawImage(img2,c*tileSize-tileSize/2,r*tileSize-tileSize/2,2*tileSize, 2*tileSize); + else + context.drawImage(img2,c*tileSize,r*tileSize,tileSize, tileSize); + } + + function drawWall(r, c, adjacentTiles) { //GOOBY + //drawRect(r, c, "#976537"); // dirt + drawTileNew(r, c, isWall, 0.2, "#976537"); + context.fillStyle = "#95ff45"; // grass + drawTileOutlines(r, c, isWall, 0.2, true); + context.fillStyle = "#895C33"; // dirt edge + drawTileOutlines(r, c, isWall, 0.2, false); + + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } + } + + function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle){ + context.fillStyle = fillStyle; + if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10,br:10}, true, false); + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10}, true, false); + else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {br:10}, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); + else roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); + } + + function drawTileOutlines(r, c, isOccupied, outlineThickness, grass) { + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + var complementPixels = (1 - 2 * outlineThickness) * tileSize; + + + if (grass && !isOccupied( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); //grass + + /*if (!grass && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!grass && !isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!grass && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!grass && !isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!grass && !isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); + if (!grass && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!grass && !isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize);*/ + } + + function drawTileOutlines2(r, c, isOccupied, outlineThickness) { + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + var complementPixels = (1 - 2 * outlineThickness) * tileSize; + if (!isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!isOccupied( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + if (!isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); + if (!isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); + } + + function drawSpikes(r, c, adjacentTiles) { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = "#666"; + context.beginPath(); + context.moveTo(x + tileSize * 0.2, y + tileSize * 0.3); //top spikes + context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.5, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.8, y + tileSize * 0.3); + + context.moveTo(x + tileSize * 0.7, y + tileSize * 0.2); //right spikes + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.8); + + context.moveTo(x + tileSize * 0.8, y + tileSize * 0.7); //bottom spikes + context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.2, y + tileSize * 0.7); + + context.moveTo(x + tileSize * 0.3, y + tileSize * 0.8); //left spikes + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.2); + context.closePath(); + + /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ + context.fill(); + drawSpikeSupports(r, c, isSpike, isWall); + + function isSpike(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === SPIKE; + } + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } + } + + function drawSpikeSupports(r, c, isOccupied, canConnect){ + + var boltBool = false; + if(canConnect(0, 1)){ + context.fillStyle = "#444"; + context.fillRect(c*tileSize+(tileSize*.3), r*tileSize+(tileSize*.8), tileSize*.4, tileSize*.4); + boltBool = true; + } + if(canConnect(0, -1) && !canConnect(0, 1)){ + context.fillStyle = "#444"; + context.fillRect(c*tileSize+(tileSize*.3), r*tileSize, tileSize*.4, tileSize*.4); + boltBool = true; + } + if(canConnect(-1, 0) && !canConnect(0, 1)){ + context.fillStyle = "#444"; + context.fillRect(c*tileSize, r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); + boltBool = true; + } + if(canConnect(1, 0) && !canConnect(0, 1)){ + context.fillStyle = "#444"; + context.fillRect(c*tileSize+(tileSize*.8), r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); + boltBool = true; + } + + context.fillStyle = "#555"; + if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING ONE + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4,br:4}, true, false); + boltBool = true; + } + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize, tileSize*.6, {tl:4,bl:4}, true, false); + boltBool = true; + } + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4,tr:4}, true, false); + boltBool = true; + } + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4,br:4}, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (CORNERS) + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4}, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {bl:4}, true, false); + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {br:4}, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {br:4}, true, false); + } + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tl:4}, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4}, true, false); + } + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4}, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tr:4}, true, false); + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (OPPOSITES) + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + } + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING THREE + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, 0, true, false); + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); + } + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, 0, true, false); + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + } + else{ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.6, 0, true, false); + boltBool = true; + } + + if (boltBool) drawBolt(r, c); + } + + function drawBolt(r, c){ + context.strokeStyle = "#777"; + context.beginPath(); + context.arc(c*tileSize+(tileSize*.55), r*tileSize+(tileSize*.45), 4, -.7*Math.PI, .2*Math.PI); + context.lineTo(c*tileSize+(tileSize*.45),r*tileSize+(tileSize*.35)); + context.closePath(); + context.fillStyle = "#777"; + context.fill(); + context.stroke(); + + context.beginPath(); + context.moveTo(c*tileSize+(tileSize*.43),r*tileSize+(tileSize*.47)); + context.arc(c*tileSize+(tileSize*.48), r*tileSize+(tileSize*.52), 4, .2*Math.PI, -.75*Math.PI); + //context.lineTo(c*tileSize+(tileSize*.4),r*tileSize+(tileSize*.6)); + context.closePath(); + context.fillStyle = "#777"; + context.fill(); + context.stroke(); + } + + function drawConnector(context, r1, c1, r2, c2, color) { + // either r1 and r2 or c1 and c2 must be equal + if (r1 > r2 || c1 > c2) { + var rTmp = r1; + var cTmp = c1; + r1 = r2; + c1 = c2; + r2 = rTmp; + c2 = cTmp; + } + var xLo = (c1 + 0.4) * tileSize; + var yLo = (r1 + 0.4) * tileSize; + var xHi = (c2 + 0.6) * tileSize; + var yHi = (r2 + 0.6) * tileSize; + context.fillStyle = color; + context.fillRect(xLo, yLo, xHi - xLo, yHi - yLo); + } + function drawBlock(block) { + var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); + var rowcols = block.locations.map(function(location) { + return getRowcol(level, location); + }); + rowcols.forEach(function(rowcol) { + var r = rowcol.r + animationDisplacementRowcol.r; + var c = rowcol.c + animationDisplacementRowcol.c; + context.fillStyle = blockForeground[block.id % blockForeground.length]; + drawTileOutlines2(r, c, isAlsoThisBlock, 0.3); + function isAlsoThisBlock(dc, dr) { + for (var i = 0; i < rowcols.length; i++) { + var otherRowcol = rowcols[i]; + if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; + } + return false; + } + }); + } + function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { + var cx = (c + 0.5) * tileSize; + var cy = (r + 0.5) * tileSize; + context.fillStyle = fillStyle; + context.beginPath(); + context.moveTo(cx, cy); + context.arc(cx, cy, radiusFactor * tileSize/2, quadrant * Math.PI/2, (quadrant + 1) * Math.PI/2); + context.fill(); + } + function drawDiamond(r, c, fillStyle) { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = fillStyle; + context.beginPath(); + context.moveTo(x + tileSize/2, y); + context.lineTo(x + tileSize, y + tileSize/2); + context.lineTo(x + tileSize/2, y + tileSize); + context.lineTo(x, y + tileSize/2); + context.lineTo(x + tileSize/2, y); + context.fill(); + } + function drawCircle(r, c, radiusFactor, fillStyle) { + context.fillStyle = fillStyle; + context.beginPath(); + context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize/2 * radiusFactor, 0, 2*Math.PI); + context.fill(); + } + function drawRect(r, c, fillStyle) { + context.fillStyle = fillStyle; + context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); + } + + function roundRect(ctx, x, y, width, height, radius, fill, stroke) { //Gooby + if (typeof stroke === 'undefined') { + stroke = true; + } + if (typeof radius === 'undefined') { + radius = 5; + } + if (typeof radius === 'number') { + radius = {tl: radius, tr: radius, br: radius, bl: radius}; + } else { + var defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0}; + for (var side in defaultRadius) { + radius[side] = radius[side] || defaultRadius[side]; + } + } + ctx.beginPath(); + ctx.moveTo(x + radius.tl, y); + ctx.lineTo(x + width - radius.tr, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); + ctx.lineTo(x + width, y + height - radius.br); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); + ctx.lineTo(x + radius.bl, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl); + ctx.lineTo(x, y + radius.tl); + ctx.quadraticCurveTo(x, y, x + radius.tl, y); + ctx.closePath(); + if (fill) { + ctx.fill(); + } + if (stroke) { + ctx.stroke(); + } + } + + + function drawR(r,c,fillStyle){ //Gooby + context.fillStyle = fillStyle; + var cornerRadius = 20; + context.lineJoin = "round"; + context.lineWidth = 1; + context.strokeRect(c*tileSize, r*tileSize, tileSize, tileSize); + //context.fillRect(c*tileSize, r*tileSize, tileSize, tileSize); + } + + function drawGrid() { + var buffer = document.createElement("canvas"); + buffer.width = canvas.width; + buffer.height = canvas.height; + var localContext = buffer.getContext("2d"); + + localContext.strokeStyle = "#fff"; + localContext.beginPath(); + for (var r = 0; r < level.height; r++) { + localContext.moveTo(0, tileSize*r); + localContext.lineTo(tileSize*level.width, tileSize*r); + } + for (var c = 0; c < level.width; c++) { + localContext.moveTo(tileSize*c, 0); + localContext.lineTo(tileSize*c, tileSize*level.height); + } + localContext.stroke(); + + context.save(); + context.globalAlpha = 0.4; + context.drawImage(buffer, 0, 0); + context.restore(); + } +} + +function findAnimation(animationTypes, objectId) { + if (animationQueueCursor === animationQueue.length) return null; + var currentAnimation = animationQueue[animationQueueCursor]; + for (var i = 1; i < currentAnimation.length; i++) { + var animation = currentAnimation[i]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === objectId) { + return animation; + } + } +} +function findAnimationDisplacementRowcol(objectType, objectId) { + var dr = 0; + var dc = 0; + var animationTypes = [ + "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK + "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK + ]; + // skip the current one + for (var i = animationQueueCursor + 1; i < animationQueue.length; i++) { + var animations = animationQueue[i]; + for (var j = 1; j < animations.length; j++) { + var animation = animations[j]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === objectId) { + dr += animation[2]; + dc += animation[3]; + } + } + } + var movementAnimation = findAnimation(animationTypes, objectId); + if (movementAnimation != null) { + dr += movementAnimation[2] * (1 - animationProgress); + dc += movementAnimation[3] * (1 - animationProgress); + } + return {r: -dr, c: -dc}; +} +function hasFutureRemoveAnimation(object) { + var animationTypes = [ + EXIT_SNAKE, + DIE_BLOCK, + ]; + for (var i = animationQueueCursor; i < animationQueue.length; i++) { + var animations = animationQueue[i]; + for (var j = 1; j < animations.length; j++) { + var animation = animations[j]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === object.id) { + return true; + } + } + } +} + +function previewPaste(hoverR, hoverC) { + var offsetR = hoverR - clipboardOffsetRowcol.r; + var offsetC = hoverC - clipboardOffsetRowcol.c; + + var newLevel = JSON.parse(JSON.stringify(level)); + var selectedLocations = []; + var selectedObjects = []; + clipboardData.selectedLocations.forEach(function(location) { + var tileCode = clipboardData.level.map[location]; + var rowcol = getRowcol(clipboardData.level, location); + var r = rowcol.r + offsetR; + var c = rowcol.c + offsetC; + if (!isInBounds(newLevel, r, c)) return; + var newLocation = getLocation(newLevel, r, c); + newLevel.map[newLocation] = tileCode; + selectedLocations.push(newLocation); + }); + clipboardData.selectedObjects.forEach(function(object) { + var newLocations = []; + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(clipboardData.level, object.locations[i]); + rowcol.r += offsetR; + rowcol.c += offsetC; + if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { + // this location is oob + if (object.type === SNAKE) { + // snakes must be completely in bounds + return; + } + // just skip it + continue; + } + var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); + newLocations.push(newLocation); + } + if (newLocations.length === 0) return; // can't have a non-present object + var newObject = JSON.parse(JSON.stringify(object)); + newObject.locations = newLocations; + selectedObjects.push(newObject); + }); + return { + level: newLevel, + selectedLocations: selectedLocations, + selectedObjects: selectedObjects, + }; +} + +function getNaiveOrthogonalPath(a, b) { + // does not include a, but does include b. + var rowcolA = getRowcol(level, a); + var rowcolB = getRowcol(level, b); + var path = []; + if (rowcolA.r < rowcolB.r) { + for (var r = rowcolA.r; r < rowcolB.r; r++) { + path.push(getLocation(level, r + 1, rowcolA.c)); + } + } else { + for (var r = rowcolA.r; r > rowcolB.r; r--) { + path.push(getLocation(level, r - 1, rowcolA.c)); + } + } + if (rowcolA.c < rowcolB.c) { + for (var c = rowcolA.c; c < rowcolB.c; c++) { + path.push(getLocation(level, rowcolB.r, c + 1)); + } + } else { + for (var c = rowcolA.c; c > rowcolB.c; c--) { + path.push(getLocation(level, rowcolB.r, c - 1)); + } + } + return path; +} +function identityFunction(x) { + return x; +} +function compareId(a, b) { + return operatorCompare(a.id, b.id); +} +function operatorCompare(a, b) { + return a < b ? -1 : a > b ? 1 : 0; +} +function clamp(value, min, max) { + if (value < min) return min; + if (value > max) return max; + return value; +} +function copyArray(array) { + return array.map(identityFunction); +} +function getSetIntersection(array1, array2) { + if (array1.length * array2.length === 0) return []; + return array1.filter(function(x) { return array2.indexOf(x) !== -1; }); +} +function makeScaleCoordinatesFunction(width1, width2) { + return function(location) { + return location + (width2 - width1) * Math.floor(location / width1); + }; +} + +var expectHash; +window.addEventListener("hashchange", function() { + if (location.hash === expectHash) { + // We're in the middle of saveLevel() or saveReplay(). + // Don't react to that event. + expectHash = null; + return; + } + // The user typed into the url bar or used Back/Forward browser buttons, etc. + loadFromLocationHash(); +}); +function loadFromLocationHash() { + var hashSegments = location.hash.split("#"); + hashSegments.shift(); // first element is always "" + if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; + var hashPairs = hashSegments.map(function(segment) { + var equalsIndex = segment.indexOf("="); + if (equalsIndex === -1) return ["", segment]; // bad + return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; + }); + + if (hashPairs[0][0] !== "level") return false; + try { + var level = parseLevel(hashPairs[0][1]); + } catch (e) { + alert(e); + return false; + } + loadLevel(level); + if (hashPairs.length > 1) { + try { + if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); + parseAndLoadReplay(hashPairs[1][1]); + } catch (e) { + alert(e); + return false; + } + } + return true; +} + +// run test suite +var testTime = new Date().getTime(); +if (compressSerialization(stringifyLevel(parseLevel(testLevel_v0))) !== testLevel_v0_converted) throw new Error("v0 level conversion is broken"); +// ask the debug console for this variable if you're concerned with how much time this wastes. +testTime = new Date().getTime() - testTime; + +loadPersistentState(); +if (!loadFromLocationHash()) { + loadLevel(parseLevel(exampleLevel)); +} + From 9bf343ea806d1bd4a0f346eaedcaa274beb7787d Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 16:01:07 -0500 Subject: [PATCH 010/577] Add files via upload --- Snakebird Images/Apple.png | Bin 0 -> 27977 bytes Snakebird Images/Apple2.png | Bin 0 -> 21375 bytes Snakebird Images/Banana.png | Bin 0 -> 18537 bytes Snakebird Images/Cherry.png | Bin 0 -> 39242 bytes Snakebird Images/Cherry2.png | Bin 0 -> 155539 bytes Snakebird Images/Grapes.png | Bin 0 -> 48826 bytes Snakebird Images/Peach.png | Bin 0 -> 22131 bytes Snakebird Images/Peach2.png | Bin 0 -> 25501 bytes Snakebird Images/Pear.png | Bin 0 -> 24856 bytes Snakebird Images/Pineapple.png | Bin 0 -> 71082 bytes Snakebird Images/Slice.png | Bin 0 -> 88690 bytes Snakebird Images/Strawberry.png | Bin 0 -> 33997 bytes Snakebird Images/g16093-512.png | Bin 0 -> 25878 bytes Snakebird Images/pinwheel.png | Bin 0 -> 38782 bytes Snakebird Images/sky.jpg | Bin 0 -> 121572 bytes Snakebird Images/sky2.jpeg | Bin 0 -> 162621 bytes 16 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 Snakebird Images/Apple.png create mode 100644 Snakebird Images/Apple2.png create mode 100644 Snakebird Images/Banana.png create mode 100644 Snakebird Images/Cherry.png create mode 100644 Snakebird Images/Cherry2.png create mode 100644 Snakebird Images/Grapes.png create mode 100644 Snakebird Images/Peach.png create mode 100644 Snakebird Images/Peach2.png create mode 100644 Snakebird Images/Pear.png create mode 100644 Snakebird Images/Pineapple.png create mode 100644 Snakebird Images/Slice.png create mode 100644 Snakebird Images/Strawberry.png create mode 100644 Snakebird Images/g16093-512.png create mode 100644 Snakebird Images/pinwheel.png create mode 100644 Snakebird Images/sky.jpg create mode 100644 Snakebird Images/sky2.jpeg diff --git a/Snakebird Images/Apple.png b/Snakebird Images/Apple.png new file mode 100644 index 0000000000000000000000000000000000000000..d674834a6bbddd661b4aa12cc9657c61c8db5ae7 GIT binary patch literal 27977 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 z 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 literal 0 HcmV?d00001 diff --git a/Snakebird Images/Banana.png b/Snakebird Images/Banana.png new file mode 100644 index 0000000000000000000000000000000000000000..a24a6dc7cc46511994aa1bf9a698dbeeccbb806c GIT binary patch literal 18537 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 literal 0 HcmV?d00001 diff --git a/Snakebird Images/Cherry2.png b/Snakebird Images/Cherry2.png new file mode 100644 index 0000000000000000000000000000000000000000..9ee0a9a7240051dd04cc1a2ba4d213f0f1cb944e GIT binary patch literal 155539 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 z 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 literal 0 HcmV?d00001 diff --git a/Snakebird Images/Grapes.png b/Snakebird Images/Grapes.png new file mode 100644 index 0000000000000000000000000000000000000000..cf43a36c9176f51943f19262e5eb601b0e750f4d GIT binary patch literal 48826 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
  • VVfqvd0Bp{jLxY*o?H2jIriGe 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 R74R;Uyo`!;gOo|={{dQJC9ePg literal 0 HcmV?d00001 diff --git a/Snakebird Images/Peach.png b/Snakebird Images/Peach.png new file mode 100644 index 0000000000000000000000000000000000000000..8b98509b0eb6f9e4eba68bc3643dfa5061e165fb GIT binary patch literal 22131 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¬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 ZEo}J0-FAHdUc15f%h^jNZ%#Xe{13mRnuh=Y literal 0 HcmV?d00001 diff --git a/Snakebird Images/Pear.png b/Snakebird Images/Pear.png new file mode 100644 index 0000000000000000000000000000000000000000..a7751e5dd3d430e289019a493e19a7cba163f424 GIT binary patch literal 24856 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 W?;h$d6!^!3SzDcVIF&g1#{L6Txborv literal 0 HcmV?d00001 diff --git a/Snakebird Images/Pineapple.png b/Snakebird Images/Pineapple.png new file mode 100644 index 0000000000000000000000000000000000000000..5046af1ea6261748398e26579fadce341076f6d9 GIT binary patch literal 71082 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 BD^maf literal 0 HcmV?d00001 diff --git a/Snakebird Images/Slice.png b/Snakebird Images/Slice.png new file mode 100644 index 0000000000000000000000000000000000000000..4786f1e4108d91a5add217898325760f7bcd75fc GIT binary patch literal 88690 zcmYIPby!v1)1|v4q`O<`<^s~)9n#&6#HG7K=@bN|yF(C=?rx-0I=_Ry{=Pr-;X&`Y zd(WP|X3d&)B9s&)QIQCcARr)6rKR4fKtMogz5GFd1AfzP{&5Kcf(%0Xors#J!C@A> zC(-of)#|+dWwmunqHU9hE=#qkZYp6YjHoo_Tx~E2!UO69`E4;qG*)M-PZxF=0U7qV z{F{&FWPRAz_GQho8dcu9MB*HXjL(CmM+q^4igx|b_Ct>?dQ0@*+Mx``=PdDWQCJ6k^>Q z16e|-hT#h%FpZoP6-9~l8XJUa@5ZCm7xy152SepTP?^Lkf9L+)P$vu@DOj*UKY0rY zX<_cp>}IR1%aziPM_lk7l9Sr|Val}UIWAsg;r?EI-KH|u3p2g)1O5Ws$u6;*O1>;?fjW{v; zW}v1fs^DsPXwcdFTtU+(6!mL)eL*Y9-y<=Cf@hAr`zi1oO`Cl@IMtU4Wh9+Ux&vWbDvVqZvWIA&*>N@Z#$r?#%Oq*2oo7d7i={~wnEDCBDeixtfCV4b_?dD_ ze%ed3 z5M174+P&aivwgC6z@?6KG>6V_0{s)6JEZvgzvE$qYT41t-UxJoBvYNw_=q;R5}w^h zUmWa}SYxZIIooFpEqgJ({`Bvr-q3@IU05?H23%D!gn!o_#=yzmLZIy&(JOxVpqJQe z|JIVLl7okLiTZ!ZNm1!L^HnLS$%w%8RsjOnCUxkzE8i?vA@$U!toK|`Q^C^$`e#s2 zXWaiT{#Te-3zpq+Y^qhyW2vhOD($QK!fr< z!sJE<4z6k|``^OxWIzT8s^xZ1a=L>hMXw(3FA|3$ou(%S(TTbuJcK~1G5&MxY+IBp zA01>EW0uCJze~<{vRz1m;Vu3_XJ}_tuS{Rj z_#@c&P&~0{`ZK~3zxVAg0@9ZAvRMG*%8u3s{zY9$G1q85(C_oy=`EsaA1gvQ3VPtw z)lS=!E#kSs2WV8Y?EunXBL&ZrTK)!k!`dS0$Nk6Os9co~E{2{O|I%H6BEHRf zX0EcZu%p)^`o4(1b7S12&Gnun^KMO*=U`uuKu> zrf2itVvL}&vHG>y9lYN?3(4AA75tDkulcd+I=|grrMW6{+f|VJ%+)*)k33AX*B~!% zmgAa&$w%T4I)3W);U9j;t?@(M+WdMJu$~$-o5>4;)BiYhj99$CNvnK1D8W-&`be#I zQ;In8pd4q%lDdX&t)H!Adymgm`C;>i1N(o#KbF#o>!FAuy_?3>!}We>qEblu%#OOo zhwV%LXou*y#p0T+<;9khd`<#cRuI)F8eN1pBQN968^qg29pFhY{T2UvQdDObynhxR zCeH7SU@NR=64NNuv;}GNYf}aJIyXAcZ96sG%+n|(@&Fc9gmhFUMFle9e^sl~2*#bfEr^e0^xsY>xFSBBWFjqkcAUCMT?GNPIcFvD=EC0K)x|3Wwx4tiQ>+9Q{i zey%KvdrTPEn3osfROP*VdY$~C4T~l0i~&)<2!n%A%NqEqpa0;%0_yhQwccx?lIMw! z$~_XFn7WBHS9Qh3=6Sa|E@<{6Wl$77i$%v+*0Mt&`ja8X<}e5dW)} z7_w_~&9LkgKd4w6&<+()xqfm-*U9ryFzcAM#s=ep z<~q-z2s*m|twR>7<@FQAAi<(dsIT)v;us0y+x8`FHTF>x2ixwZHh41rmB%+GR->|@rb_7#UQyI-aLvryC6j; z_eHdR`99iKvA&!Gv9eir3D(zyS_GtO$Jzfdg%;*~b|mZdOvR{}(-#vOnb)H~S3D;g z(k=F7WfJa}Y%G~7-UzG{vt50n-V0Se!$NoGdU=Mm0`dPJ1vHe`!O4x))EM|@ekeMA zz8hN$?WAzarA_AT7IGs&46a%l)dMpNkF|P*y0%}u?+K#dHjuvp7QKr9f`B1o^c;;3 z&YRq{Sm=w@CYWi^%r_V~BxVkLC;8jJlh~~onf#}-WSq_24rb-5ZGr=j9=5Nexkjq$ zWEYJ42wW=Y;}Xt4Bv(W{^f|4+IqhE~++a;_q?@ykI;}g5DcsDKnA~-$iWfg9=(br{$U{o~r?4*4|C!KvkmB0o^-EMp9>`89|G~?V|e&SEL?Cn)A|YHMpetL8c}y)c_t|AE30M!x~?$;58nW7@ko{Dge< zdBSl*$HPkxC;L?qe+*K=t>6zPepVMNBWt}cg-?3xe}%7Bl+59%)h1t(mbC`$cy*Q( zDB{i1)3CHk@pa>@-zD{{A0W2kd$YP;60w*zI>+QcbY6o6_k8MzLO?;yvdZDHm$p<9 z&FlbDxh7fl#5a1Q!d=9jz$Zd6^us%@42OPx!loaqZCbWQUwGd?F#QWX4$Kwnr)hpR znhp2+sS9Bkab2+sCZ7W1bYdYLO||IO9YZk_vy`)q0?gMfnO*2NEx1vrU(w=lg#R#U zfMSCL!AmJM5}{NyPrQDEHwSWHaAahX|`FM*;@z-heuCaHI+$TRsv4RSG;Kayrp6}2lJ zu599VnJRD_uVx8ec=4Bl(Wv)-gIIv@q570U_M~y^laq-gbJXr?ahU1xg>n~Zu5IZz zv16BtJ4r-hd=GI>9+H#mq1PSp=^YqA=14qJoj3l?oG~*5Q(=xC^VskX7C-AdVX+On znGsLbvB}|6O4gYj^Tu-0$GIQH)SYvI5#KrimNbdgJNhqaEki)Z6B+QZKWJCpX9)PY zgFLm2EZXRI_kP{Q;mVeVAa7i%Cg>U{M5u9(;x#fS$okrX$&%CERSZkLxR*{TL z8Tw^^DR@cB`Z|&-$<^()tFNNiVSZvu(V|?J7{MQE)a7rez$3D`Mn}Y&x=CS7HE4u$ z9qcJ>ucVg@TeUE^)IU2;u1d0Avkt&SftTVqW@{iTXP3OmmeiNn1w)1g1O+fl5+8RNZ6<~e$ANg;W5S`gWi;4O9 zlztXD$xr@WPUCs{f}fU?vRP-IP?>O>l^e-y4OO*r(}TXOAvsDXgY~fzyp1gAm-b(%sK6n} z@0;hj{LL?Rm48yeUrFzmbHfTQ>j^h0Ye6B-s?8DW7PGP$RD*#uQ2bvSEC+Vx0hgX| zX_9Y}%j!WaFXF1?_ydrAsMmz7slk^biJPMXakgKsT#t1Gf54?`m^K;y1+86Im@DQi z&Q1ctILAdxbZ$F}M2Y2>;g3=tvlf(^iPtN|?w&AUq6CyxnW8&TOQQ zOm{uj7T;e8*gCE5x;0z5bqv)yVHDLP!)?MaEj1qPd?#G0A+dZm%HRCheaWl`!@g*u zW)ADQT(D^3e3=5o4=(892ClFtYi#tC5_2RNs2*?$dFR+cGDdz*F#3V)VEpePSw}U3 zPf*mHP!p)&q6EUEn&>281F}=#9lyWqJy-QrzoDng8)J%!m<%31_OBi)t)l~nG3uZZ z!pPaub)vPBkk4q?ssWgMhrWn!JmE0#AUkhH?*=@Cp{z^>6u=TigGtl_p3QyAK08~* z^%`G3sLyToodj1FIZFPkcmkA;AJ$L2c{U6DGTzud7zS+^cT*4i7$wJ7pRa(LE{2qh zsSlkFku9uz|IWc^iiynp0?J1G^_7V|jOHLuq$NsK6mlYhS{+kx=I`X-g*<`7g zCaSl=VQoMWEH(=m& zAC@aGNmB^kBCevPy<-3M_S1iQk*5fm|8Q&0J2d={_?*^rbV9-qvca~Qrefj{LmhMx70)@Z29Irxyw1c1EB=yZ z&<;iX_34R4Uo=TQle1CBiqJB)Z7KAX0958Y9EaL|hD{M%6E8+MF=X_;Fd0uD24$J& zqI>4kDSIPPpEMV!TgK(1>+0@y2K`%w**>_`@JvOW=}%fU%6DO>TaLt3N)j z)3klxZt>nL>b1yh@Ef4(dV~+&`LE0vyyAHnUAzmq2>+Dv#%zfgtYK5BXy(B18%$h= zL+zfHW}Ij6t@}q>e?Nty#zIbjQpT~w%$Mti+?$`oeKK596T|DTf6E5V*iCSfN24;4 zjikK6KG`(Da(F+ zx7vE#aTB8^G{x7B1^u)GR0m}_%?2PA_9b3q|HUHcg_z@pT%EMcaoG>S01w=1gC_FD zFJV6KFm>mAvn(+qW%OVeutujZs0~}u9&`>JM$YdRGv+HR8LEdc;Hv(@PO@Qh=Q~wg zK)2d|AA4#8(B;<;Ox8DRMan(!=x6kwvM#=&2_a**qEDsWI={_7j+FwO)lF5{3|h7ry07PNQUtiethAXJjg66~4M)q$ zYZI(gXa*_{9Lm>q+BehRz>Z0AUYZ`!C}1Mdu#;&guP!Gdv8_2nl+&Db7yTkL+KuVV zHH37XR0@-zc5!}sM6!;}3O<}jG+T^HAhSziKIf!I_ji=2fEoj;p<|;b!hb=E?R+ZY zrVS1adFFe+|NTDjs2(9_aAgV`s$~YE2%e*zUMe(2{ERAO4qQnBQbGa2VML^A*iFF1v`9%;<%4vG22=`63n>A8pS7jF~d-8e`QI$w1P1FVc z<9DveP+p&0!eD45o;z;nvFxjYL*Z^N)ERjp4z`}Fr+<})@)p~AA^tw+Mqf7X3XLcwo% zKaCu|yV(5xQn0L$h;A8uD)T%6C{(hbAq=ApQ8FHlw8CpFLhb_B9idGsLaMEv?Pdn* z_vi1e#wmu`kLNol*5;hk{sSgvaBJOfmKeM_VRrMO@V7!~ZF#zZybh35R1ADXvw>hy zCvq+_>u^lWWPzK9MBK7NG9^E)fghO5B_P*|JrELgn~h;Z<+&vZlEE^9MH?Imui||F zN8Rx?PxCu=U5?SlYojp1EYANiK#&iVSJ}=;xB`CD6knsi;i^5-U?;d39C#fN>Wmsw z20@mO4pcXUXeIb?=PEkVuL-}3MG6AP3U(lTSzzTL2~bY;(~|vDeqa175%gNQQ=Ac4*w^j>?YM!JTP35r z$xxkRtOpzXMN%Zxa8D@rSM8mLpf4pA+Q%Do{qw3wp=ZpHoDc7{s#};gqnUoD711d0 z<+^mHfi0A z*~Kwk{|9nH7(i3`q-L|4jXvKOH+X>vE}>)2U&!7R-PHaF%8FJcntl$ zRx23s7DI1#$MO$Lny z3D7{28k77tGKp_+9=VA(5InB2h;He|Haa_6d^Z6H)Nk=coKMi-Oz{>LxSK_!wk@Re zlKr@0{fd{4uQUc^zKJD9k!6)NQ{?8MI9hE;ogKR>mpE=6fu74au*jH~t8i&o9}!r> zG~7rR4V#&MKBt&1m8gFlYY;nJu0PZLM*`ca;~TuM;wa(Jv@kRH7{u8!eD7K6`rjlU zUZN{vcvUiyui|TORZ*bhc+K?(ZI8x8_t1X=y>l3qxi8U^H4&$-&bdJc*hI99J1dt+ z`=O=Pg#mMSa67SS%9~rKzcDp}+QI7AZ&=fOOBu#ohlW44T3pRNWi>rujvq?7@bisp zlwEQ_Aw6hcFfyS;g#UIGUAfvf&IvXb?6WUcN;;rLEhN_umkI|T+G6^rZwFr?9%{QQ ze&j4UUYLvcBHQhKS$ms0gtoTy%4n7#mtwVX>$JRa4=9t}s{uDoE7A(Co!|8#_zvuN zVkW*PZe8ms=oO0t@bk6&2D;1UkCbrp7JLY_noQ#}i&!)<9ke_wd{f1y?m8A{EJoMf zy+PvSJod(j@6e$?GhLOZ8pE?Y&2Vq*VvQ1hiBM;doiJ;no>|WC2?j(d!O$hbzZbJs zY;9~%o01aq&|l_bre7N`Pru})5?yaPx)Agf_MN|is)ZmvRciVjJlP(Fe5+RR$~|7M z;Sn2)9NqfpW!JQgco;x__rJnt?+m|OzFkuo=d{suqLqs4p!x_a)ekH_Vm6~*Sp6d^ z*rR4KNL(Iled+St)vRyqU@`FMKOpq<1b4!-qzQ<*zF_UTWC;I%0YnB=fOH?Tsnf1c z%9LR-05GBAs}?%B9r^}Dk{>Ylj1f1a*^9-de~YjU8h|J#{ZOi zn*N6|^Sz3P{9<&}dXTRw!5Tv}M?0{S5lH1w=@5iTVEfg0Q>NJ06&))TL9ce91rtO( zG`agG59K!YgUwj_xIfsr>kQ+pIn+UAtW-hmwAoj9 zr*{>)i+uulC4{6#Vgjk`&&y1J6UYTT0#a6b`$E2j7{u1J;>oJTJqN=q;1>_eXGk;4r&P zb$%ra)O8r~8lB2?ZKo1NH>UttfNoIL@N% zIu4w?3Y}_{SHsRDr$zqBF@dfLkV%3`Q2&n9$J!8xM)k&eaDWRSWYTRIcv$s5ack3} zR~!BC5!dltH8+99wJM;*Fq_U|Y^UL$7l7?6ix&}sBFx%mc1{BbI01@ng73;_Ke0NK z{u`fuLolsq^?g^e?57Cm_RCNLXOYAI-{@_P+s~{6n#w@q%ko@5X&YF!sC$6MW<~)K>2XO*X`~ENn1j zs!}HrN`q_Y&%Ba#ew*nu!blPnIc)~L>aMXjd7vh^Re!qgq>%q6q7NTIUCm8tVdz93 z@ddqaq>_3)ex$T0{l41nY!YMY$?a`dt@;%pMMj5&Pz5RS76jq}b?2E5X%NFRR71k+ zXRE$SEb=R6fj17N_eHc$k#tVTse4r}VM4|GZh#XQ3h#m(xnIy3d<=Tg7Y;W1Xe=bq z4rg`y<+}!OJMYU zIDl7b?l8mpz;Ua}zo05#rA<@5lj-lb7_m1Zzo0WnleY4Dl>43JMR>YZ2FH6R%h6!V z90w%K%Icubkva%`?dqB`$|(~KNh|a#8G>Ag2Aa__BptRU1hTV z(&IL?Y@w?Ke<%BA@_vQ1F+agQxnw);bkY;3^OLzRX+=|9Y5t z#Wn;aT!Qg;{lK}HeIGgd_~%>{fOF~ny7vnDj=4TY5ua6i$haMs*8xh>5OQB;idxMB z${_l|riqXrcl0pk=i^&8B_3u)>I10zc4vR^mS{VX^U*BgD;+T|ic z=+TX^PKy809e5b$8Ri@Di^{G~<3P)q$`m-5NAv-$-(NBTR>?(o7~S*c5nIZSoCY63 z@qDB)A9f~<{(U!GU5YW4(Z(aF+w8IJl(H_D&ZeSK&Vq|J+o${rOVf2=?gXl3c&*e8zB z0<;?*;x(!L?{PEeX8GMz8>RU>L)hr_Z@V@?8uQ-v`|mOLY!R5wyEZYUeMqi-lp9gA%iP=@G#(Qf5`HW=H0tiM(p; zR0w3tW`y{gDX*=Lmtz`|x+O&xo`n_jr`S!DeFYKZ78F8z^z)|}q zxBb&wdP)godLJ>_@_uOda>&7&6pXxdb2ON4Zz%G!!EYSrp**G7w*hx5GegbsW*@v= zj9bDCD9^Qc2?P3Ma?3GFgb|W`ZzVZ#&vk9J|;m|4<35_Pzq~a0EYPXEqZ=?ri zgnp-gH4hLjg`@3qAbtYC)@lH@CJAiJSoMap^7?IVI?Oxur6-DQC(J&o?K23>AHd(Q z3%ZK79I_sDlnH2+mVk^dvf^$O}LctZKr)wF1AB;_0dzk@1-NE zMD39<3m!bcl&qy#7)81kGf$D{JowsbjByJghP2gR=p@5MW7Tp$>ax=&skHKbM}rB4 zb}gtZI%V@J>JM<{V%W$t)l0w~(=N_R;4_CDJBd8GQtlMOXPAX(UBEMH;#`h;IRzM7 zA&);sqg^JL^VHE3lUSq-LSf#cYmsqfasz6KhWfdnXE>x4*!_~!tS}Oq(iB`lQAF5! zjo_PZr+%f}#qcfgnQQb&^;?Qx(j-(2&2k-+vssZms^K%fjAK25XKo~d#ZXq)2wW|B)$W@*xz%@97Dzr$9K4QFrEwj+YLJqHsFTTrC&~NMYH|EFZF8KdS%7obC^kSr4qxTy$qo^RT zl7;<2zim;1jT*u+(3rn<8flvg9vt+nwpWBdJ{*u;eF_5YA*1s!(K_fW({?8ogh8)ssT|71O z;av9e`92-p^`G}3U9ZLX)yAb+0?)fF6|lLsK4ZKIgGduD3s!^W zw9pqs`{sigYt6b(bteQ5Z#vnS9DLymxZy~C&;gDfVu9;Fpm)j$6~^w*O(pPloyA9D z;TzAFHi68l12bE(0tDK33sRK2SXz)TQJH9&l6^{jBD-NdZsTFQ(>P7A%0Yv$hg zyQ^wkx8t^CO0yS5h{Ql+_1cAH-xQknQm6!*T7LGeX&H0Uk_2`>$e~( zZN4Q=9mSkCEI705K`2NnjB$oHkBRYS${6-A>j(`{W5LoVWx znIwz}d>uR#*y?ylRrb;fgChPsFre73DC$7M3D_;VzoY+YjUF;UD+^w;?_!ABIjna( z{kjKN#uE2Z$@cW7Gtb)%^fye&I9|Q+`e>@ig`M&}?}3J4Pc#u_1<(D+4u4NO!GalJ z3Dw>mO;nRg?jZV)Lr45jkncOqlEb#47m+>rN=uzQA1BH5nV@wjO*Lg?y0?0=f4#2) zn{~3B#sA?W%6|v~2?4JEH)h|%jYy=}nQJPgal!qcE!LOC<>1Qjk+p41oiWg0z!WGGrv;T&*`xX)J+F$elGnJGl(4?XR zIZe!8kV!gq6$KsT=7rqU8bLB{8u%wc{Nbi6!p)Pqyxj-+0niuDT(nk$THpwd~5KH`b9xUM3o zgd6=^UqKYiBq>}z9G!SIY@HaoaLC<;3S^$mG*+ocQ|7=ILZOi)fg4Dm_;DKg{V`$Z z3Pa+@$9~gx^i{JypXi5t^nR&7vU%t1{Ihg{pX5V5;VxihNPT3SX(Qkmw&c9tuZA+y zo9?Nccb4=SnKUKZi06Uso*TbVzPVz_9W9bsw-q_M$vDZg9fcG-uaslan+dK~oZvd# zeIqddmzs;ZWB;c~(RsylJ0@Qhlb}31&#pp>a+F|%UnMs+U0vk7nQP}vH80r59&AGvE5oqjQ^SwG5;XV(2HjRnKF`}{R=aB8Zd-f zfn1q?+fz%CwKZV}66|sQv+Jt}s~V_pufU=XNGgI|%jnQ421w!7RYu1(Hm}HD%>sJx zL@(yleq^N6MFj4e^{EuI$XLnnvXp0aecqM5BKGopCuUT(&mU_L0x;HHKCFe%-4MM` zM$|-N_7P*JiYbFuq#sz&k)c2+=puHLfx;$eJvTc^IbYPecq%$TWq4q+D@(Ah$UNVD z-i@?ti9!7ui*T0nr}UzbIob|C$co-y>R|HQ%axjPMLo9goe;0}%Yv4*DKSG(a|gr- zWY+ShK|^oyB95Cz&GHzoKOTqVQ0ET4caFw;?oaKG{TTU}cVx-&m)ZeRRy?R{!Ry6N zVx|*@NFY;HuPm+iiznGd0IT(XHSK!aH=x&!$N7t`2m9 zVU$!n3uEOmo68^gy=6r|H|gB%>;nF!O7Qe6roSNw0K=fMv~coPOLpgM(8hFhVG=OZ zAEH|ECiJPVYw8<&12+(BEFz={_P)mpxK zH`X#>)I&{~zm=eB-r-Ew-=zKeT#}5+B((bn^o6P7TdZeNX2``-0Y_W5ZMD|-k@%?} z9$z7(4hF42c;biFjSV9TMu*Fw98zR?SK;4h&q@~^6(~}!X#{3T9L9%t*Dlmwj!Y%0 zo^|#Q;RAL?Ulh!-2+%Q5%zi}Uf3hN;sz^Hp=16vz!)${+p{#~Ukf$CP<_=VM8&{RDVGhXD_$UD^gDX#s@DlDvh&9BRl|ZmkO3KS%!6a>9z!xSA`c9%VC>jD{y2~=V}OA@Y)7~p zNiB!>_jr*+@ujfs#VVu~Xf(l!_Hr`ctw582Ic1O|lK_(D%xmag{<)}L$z^^hlh+W1 z`wAo~BHuO~(U7XS2oiQzww!sxKHJ~$C|Xm3Uf^8**WV2RlLrGIuXyoee?Z-M3jo5E zLi|wj8w9B+T7s zcB82y2*fxf>zM5no`?R)P^xCJzBmRpurw^# z-bwK^PL7vw9GM00JaC@-m4xp}Tgjna7!HU>75vR*1qrpF0-SOGpwkrsk-pnvW#!F{ zk1bZ;GByT@^%>p8XE=IkY9dcKy1Bx3OZIKO5E>|_f;RSY%k08$>V9~Z)|VOi=F|_i z9+bJ`^4$-(tM7Ufh?cRI&7^hg5qlmB(i#ksl!E*<+#0ZY4$NK#E_5(R8pGLmOJzI4 zw)mSYuMDn2;mGzv1mmD-g`fz&z-0{jSHX)zUpYZM9uKcRZIRQ>7xjZ2^Z7}A>R{+N ze0%+qmxRGbQ$9JlH)UDzSqw$eA2NfG&vj=40y5yfEvgNWFp<7LKlrn$dW5ZtPuEG6 z;72wS)kH}|Rv)n-z5`&E2}vsqOT@V!!zla4h!8%Q1_H3(b@iv(&_PGGLlP{uej0%< zta+6i{5#;yHXQvUH~zTmj8tq8jJbG2)C={1+>*zcitJbjnLP1_(oBN;ZRZfnhBn3h z>9e`OtsnkNX-@iEnlly2{4ZN=3i_h^YhMHq&v`j5!`o1pFb0l-1 z2|0!;NOvjF1Bo?JFzNcLJQyh65RREttI&g#$^_D*9yC`%%ajdoG4NGVOcTOleQ$!; zzuC2OD;SGNHU7=89U4FwiIsARKHyvYUfcV=&F4D;5GK!E6UjdHGnSLz*@5{1H?Dvv zi^emLjGbEOXgdF7p2h6j^Jbss>-Z%00tGsmJ`x!^8T~T64vru#o4^+)Wp$C?Pd7CQ z)bs`neDJlQm4!1sy|pls)JhkeN{ZZSu=QKIV6di-#cspf7=XPIEuRu)qTbCeCugKj zI5Tdzj}8sqb)mxn`8kT}0laYpx+ZtDJj-lfM@;x_yZ6NdruQ8@vZ6U{a-Dc*EDmT- zWYzwtmkL^Ws}1S=Ly#Uz(G!_8TQaG-s082Y#QBG60>Qo4#;D5C7;F+!3xR`(`ZwFI zT#!XAkGjDrGoo-5-^g1%et3CqeJbOF%UoueVV^ybF}fhiQ$gKo;;YOf^-_So5M0xesRBYT_*sO#mjWd3_cCV}3UH@XkWXPOyM(7n`2nQ>pwKW;QJ zj9v-m3A|TvLCi$^ynm&|NvM(Rpq@~M@XkvP9Rg^-p2efbIIYO-cl$9-_l@^ zIA=^D!As+PNp05rObH78P;rQ)ol^haSY+>5&)DMEb>O5XUM{egaUlmDuIse zvf(>91x-A>X%hQ?={~E_Dk|V5yMmvDfP$dU_uIq;O`JP;+ z{$yOgR3!0K7>3s`z4|UpJO?1pZkCOt0C+bu0WaaP)Lul;Hwke8^ZV}s?Gfq8ZRFm7 zcN7hn*_JRZEY0^PCE(8EA{^xf!|Jks9Wli6QYjg89j3R75oRmT4`W;rs=>WHw;pA9 zFFL5n-khK;&q=eX60l}@V!k=j!-tmnxX^OF=zSm=$9T`GRJwjR#{;fJ${UTWx1_Z!e`Y!`!2 za2?jIo{WrbtSJi4_6r$AqaV21a+=H^hlM~Y5Wi4AX|n!=p2Ey`A49tJUK(TsgTb$Y z=;pmB3P2Da`zNYd%B?wLU8LfaWOy^x%8rXz<@dUba1^uiKZ zv~&57e~k|voW%GGJ$0ktxT>glg$Uyn$(pir<-)cy!eQqmz_q7man$%z$48T#a5&!~ zqPlO@H9M9k9~v|(CVazKrn5CWsu*G>o4Q|-<}Nj@NF=g1r8G&H!4w>Ffxha#ooM>X zs@kfVFIHo60(GZXs%MHZwLg;CI}RAXGz*?oP!pN-`DpUau=WD;M*+gLpm!Yla;e4F zjD9U$%z-12H) mIjUq_YLq{UxX6Cm#MB-J#3@;>j03%&ofoTdd8&590Y^Q8U-hMi&C&t?EYn zmHSQ{shR{B#%a$gq$)KuCevIDHK%p}{;mCT)&%OTtKW;QaVT7YB;AUbuQCU?oe0V% zbrfVWMHc;I`-3r<3(~vELO1QnlH~H`E@9sZ-zW#+Y{qSoPjQ{=j33FKpO3MAJMWnq zio(3~F*x)pnY5c#r7z^8=FREOa98347l*gko{faSrH`ZlI?{Lh@B|$ z*72I3y5;>z+dllh{%Qlfw|K;S4ZQjYygaPbc*y;}jyz#@v9Fi~?O>T*p~lo5$<5BN z+|wj;HHyyF*xODnt6SZ)RSET-VJl8D^t&ecI@cDJcvtbC$@Iy;W)ObASx-m7oPc+k zfpoR0WUJ8L&gSTS$W4Hcavcra#4e~(-;4T%DOEV7Xb~?%p72g`7{AwOs#*IUa#F*W z7MH@Zb?f?_lQ@n(5_)LeN!)h(VjrB&m* z7CP{AlWO^**(e=1F>HOeVguN3KpyJ5m->)w;05_Up+%vu{^|eHw2FPW( z!yNkOk*^K*38Gq1;6(+?Gdc!l*{^SCIn0Z7q_ivZC~0Db(8!(b-uj9NYyZ3eVSD+} zw5zQAFK>UiHJUxVc(L_UKr8$6sy*J zpdo5{f6puP#EUw(iANTP3rKj={hUM@2-;?u6#Jc$E(VSnhI7Jg4_>=H4);0VkPIk+ z6z!ELb4H54o*>NK80BlIVM#Oj9%5VoxMW+A1&DyJei9*b*lx|yNrGpIkRcITG94dr z3aRetRA4KQ#XsPD1I3@xnWw_DMQ$xyl_j9MMQmN71jF~`itN#WVU?0^br1ng!2AG4 z%9cZD`1cYwI?oJF${Ju4>Y2_Jp=-)Iqn3)ngu0LOI?S5fF@y&K79_tZ3ADz$d@x%f z$nsuQy|X`JiL>x|a~%|i2Ujqv^Rqg$C6kpjixKD%S1bna--gi*45?Wz==bv~ouMfg zr28hDE+^W`bI&j3fv#R7t{^@iuw0VlUiSifeVP8p*H-Rdb_i@Z4-}|i(GthMX1?Qc zAA(DLCg#t61?-sM70<=#!<L0KN1#d;cVW zgCG=eW=aDZN}R1vjgpx!vwKt!dvvLzas3{6bs37}wF3JpNq~n7C|~cr#Wt5dUl_CN*rb zQ`Q6sNSkn{N&qVEDv~+e9+HNk?>F$cFYT%U@vmh%SaShAN#tfDVY-kcJhco{x)VS} z>~-FBco*lcj!?vPTnY`kpUmppPQiFZsF`>hUAU}%0UkPSr9i2e47BleK>IX$o8q>0 zDtB<&1jqm=ZDyjz%y*TB~ zY1jLf;~u5UR#K05fJNV8+y_Wdd{-FyT*qU>ad0@DlQUd?I||pV`^xVPv{`AGcUu zokE%Uh?aW z>i)S6yjv+EG9%GQbQc*j*cl5!fBK_<jxX}r>Yy{np2{Of+Ikaa$0{VSUnus4%0toycam)yycl~fE5pL zKPaha4Wlwa_3*=D!$6?3s#1oa6&)&1et#gGzsP+2d0qGj26MCgkA6su(XTJ$;H>rh z9sY1{^Ru8~(oMjPY0IXqtMNlmBcrg=_M$e5taqR2|gAxQ8(v2WnR|YsCl46;a0%s!vR)Jbo7XL zfgV7#6)8RT=B^Rn7v5hVhE=1<6x8yb+&KfbfuTU=F&s!}tSZ42K?I0wpMlHv%dNNb zY8$lY*Ez3&APOaF8z6{-5Pq@LXicu#j9$`jRqVfxkb));mO1xz%v9ly7qFM-9MmHi z)Q&NrJX~&Gr2h%A*nd)Xj|?G7^7Sr}ZCTt;pGDPrrKw*Kc;{#Q+#v9yrS<(D|TNeH(YobiXi0aaL zfwOxdl}E;xl9OStH_@VCWsKom2(iv{O=nDGkjy=At?9G2nAyxFwK>DSBbeWJMsTGL z&Oc9x0a^Pk#i5VK?{4}-t-0w?%qyRy(nFIExS}4c6ueDJ0Ux+zB4XDt>4LHrJ+*Wk ze@HY%xAEm=zl}*h|5&6HwXagED57FOmLau2;G}8W%*8nwnZuj6(Fmbo{9IqrD=Tx} zPK(5!J$hC@Neu0;Rh)Xb znJKnH#7=qIk~o__$K)`+{8w&6(yG*2O%75*zpyqJ#}Jl2D~a_RDh%QJ7|WI9H`nggbqXV4VJxGEpP|F3-U#{Z2^~cr$neru#x-5`-R3d< zh*P1D7th@861*i?%z^#pS3(%A43hb5fl7N zW(^9ZU3wc(o9zii1_M0#9Rd4L7nUgHzD31k`E(+BP-zqYWv^bCPAV{}y|DnMyfR0S zv75#pjGS=|)>HMyrid=o#fpsH)hTDe!00Zp#den#6>8Qis5%3u6iT`uZ#Uv`SXkSe zq;Aha)-KyRDX^l)8xPz)-Wj=(X~$TQgpu1mI0J)8Y=rC6f?~zd-3tL4?0M*MiI@t8 z;%XOe#LYz;eqw%HEhlrLBi}x^P6r${yZE29 zd3D`OG0Z|+i9vX!w*O=+2FOSiSW5bQ{zq^V1k`?}gaq`34D$Y)Q%engJSAmI??UMD z;F|S7$GwDgt%j>m_HgxL{l#ajdEDhF!1x`)(kSH|o`^}1Sm9hxFNZED_@u|fG(On86|0=^h;~#a-Rq)h_@;;GhabE* zIe%lV(2zYx;>B&ud*Dd8hqCqMjpK;tvaI(9xj@Fk4VqriQIn7~D@i|am(R>jE!v$I zt-e7@8MXK+G!^>t&*eV8BZ_+H>}_NJ8+AP&j&S2SHH=e9yz-Wn0Cj?^`g7K&vwh_Z zQLO*7Bgn&rf~~Y8{uQD8)boUB$*b2d!BQcix1k~gM(Q8gU50RDBu37E2xS5#njV&{ zoD5NYB#B3p^=(aio9G_5Cf@YD=qONXiy2x@JLS58$4Pf>^mG&SZO|M#vLAqd2k&W> z%?Nz&<%gjSyk4S1xOK5|aN<7~?nMF3&QXmQRqc=br*mCwkZKoLcE%~><3n{z8#6s* z`OKf%sSYLzedav1{HJ|;9-INJieM7rIU$&>_c_PIZreUmFrXy%)58(D_Otwe+9@Ss zDA^o)QDUSaAA@9sES_DeO>k@Zt0#tzPe`OrXZSmV(N};Fm zj&7HdO~krziRT5u)0@HLCg@a)2ixs38eZeU$&}~PhairjGdWVM=ig@`6|F<-hzI{^ zX1pZ0`MBl(9`l0d4Ogp)+#_iFz~4g!*I{xd-v}G%nT`#&QRHSv%UP*EnM!tb|Oc(%A!&YEHr&9%NJ#4@bzj4 zKRD*mf)3GdO6tvPOK@YcYkY)_mNSp;3{Fm3BGucG1k3w^iFKMvkrUpNAz^dPNXmd5 zN)zrk?;Jd}?E{bp+#CVlBq_}Ivrc~w)0*prp`2BZfwwK`ohbgjBJpo^iupj9P~J3+ z9Mtde6LV2GTuXmdor!Z7r}9gQzr@tmqF?Ry25*MC9mC9~AaUD9J-L=mNT<-!$x8YEO={3DW|+6I|S{Z|WkewJf2Sl@w#r!z*hhNRj71g%W} zwPz6VT@SIc$XQFn#ic?xiyh|C2WCLMJaS)5kPmj=8orWnC)}moe=Lug+cl=hXf-*K z8@&WFZIfbQkDup1B9-9*ohYbk;=&=kl}I=es+B?|82B`eGU&G-mGYq!`-W{}SeiuM z_Rd5(oj!!05Kw=Kbd@$7BApwHqcoe&ghcO5738Ps|+`9zNHufkO-}db@PEnfieme0m zAl=-l)-b^kG2+Ihbo_22w?B4jYcE)~GpN%WRG~JgJHcK_eae3mxWQT(f;u=LinV&^ z+}C2bW)qn`GgF@vqw`JOQ=%1tnU+Ech}k22VDo{Q^vpi-@a1(|CNVx1@?0-bzZ=+% z8PKGF`)^1VaH05rLQ=4TCT2?ZJ%r(l3VcB2ua)(_R!6ob-KdBYl*F_U-vlwynB-lC z!!SG8SzGCs{f|xlC{EWqXi>!7A|G4=L|I$vla8#>wQ^A&16m7u&AUO6{d{`@KzKha z0kg8X4fl;y^gjVX!cwgOH&$16`}fuWDTGI}KQihuABh0kQU(v_xH}0jV~Q0VYjZyi znm8au04lXVH}2vCy2$Fm6-S=Ja%O6i8}aT*-~{bu%4)0Cvvsc3R$KH~_01jgY?j2i zJk;0y6P5QqJmv2Ss9-b^bSe!f!@-)D_$V;@zzK{YzigWqjZ%-tdA00L#+Rm4Y#FZ2 zvOTs3wc7?m;5BIng1+}sMnS;lX*Xae6s!f-D1I_>A!Mf^pLq)C1GB=cV=|cpub^&`vmtaz* zfr^u(R;JKnuZ4X;@Ru?#P;|1;=?t=@HglJ@=#7QCkF5N^NAR2we$?#;+2q_7CZx^S z97C=t;U6r${%oi5GFaqZxz_drb;xshzDjJ$y!t)Bl8O7;c)#n4h_T_;1zfm+mf%vP zd%!cs9QcUgpHS<+!AM1$MBtgj6Ut4mddZ!5o-Fi zlL}L~>xNW5WQp*3YeZ@|=oIA;Nd*m(qg$HKqS%(__Wx8HB>s}R89)(*A|TiE6uk9f zuA?#|w$cdp-t16-L;j*|KZPB#5OJ^Sx0|ia=oQW459rqut%n2sDct?bK74MdYWbp|_xBx0ECW8aP7b`KRk|V;w97e8E$~7B(M(9tp??{QbwSn(skLTf zIz?^H55%?#nekkZauAKd^p-aA8Fut01K$=#_QKv{{aq-&C=ut+m;gJYoV?Ia?2P3S ztzA8`Z#U<1m(`{y#d`!C1Sx5!J-{o)Jr64fB~mMST#kKBoJPu2syZvVr!qEz zTzikGm5p|qEZ``=H<>154Iucj=taNk15vMjHDwkiz&KS|2J{4b7ov$>LxURwclj+) zZZ64nP1FZ(@_f_=EJ8L<1F78iQ;0)EtKzA`B(78CcRIG(~IdcM&~2CODc;a~v} zg-``mMLK?+prd~X+m@4mF1SYOfjC)nF>7NFn3NGM{5b`)^LJ>1e!WfE4_YD7kKADC zuEzJQ@5K8s!F(L%EkX2QbhT9K;q)`!R(w>_U~D4`-Q<V} zjKOcBlh{OE#!MRJY)RrVGw?9zW5+k|h{;866DKl?2t^VVYFumsNW3qWa;8~C+-Yg5 zs467Dara+Ax8=ylOUUH3&^4^g3F$`>&qXTRrH>7L`u|4Y;6=w@AHGbVG=WV62OxL9 zehK&{y9K(@b?95XG8!%}UL#MmXgTp!zw-W-0^4iur*Yhs=zm4+?)&I3l@A3 zDCB)A2dFmSAY%2M--YFFpW$zc+ReV=QC>K;1!@=lXIeP8$sEXF?*{p9Xebov*fJp1%gmS4eGWL)r`FGFrqs#rcIuqqxXWy1M;Vjgq! zm%)M-$qr zi5k#^-XAOUJu#B{4Acsa1b00QpD{c2^$OeW7yk8O1x?~37U(X1;er~}UokiIuXR)j!m(c1qBEyGt-dh=>i#a)tUf0lz9b0)7mnH>LJ-&C zTK;L>9rI*8C!uub4=q{v%E7`NG6^jddX6ekhqz(E%g_DPyp{IQ>WTEB zSn?WKi85Q3HlzDuQL}C=z1v}FI9!IEqyRHC%XM&*y79N&lvhQQBD7AHmL*>aX@54I za)NgBv9K*M!&f~UH1k%*Hfx5gY2^^Aro*eZocV&~|JQ|7vwMpBJWjOcc!fYG*Ds=9 zx!Yd>Z2Ae6nqgJs2XOO6l-#Nb_mtMddi~G(dt0_2OAhWta}j5)Vk8|JG(?mG~k= zEZ3`^_)|j{o&g_W?2sZ;!gqf)%t)sY-Q)uYD_lU5)t)UeB=AHq~LKVHIe+oGePsMDTUZnJf*pUs{A%g zFa!CYMHIA~f|;;P6o#83)gQ+hb3X;)15jcYr0Iy)yq%jg`k!g8@wT@x*3U7Ws$#Zy0L%1G)1Um)og_lC* z^PG8AoTRyIr(O$pR#YW4%Z`)Kbh`^e7Spls75eRmVnC*hwPmz<)!CWZP zs4Ow^!lPd={2q7|tyE7Bo=3y1A5ITQsUUROXYOd;H^1+FrC{!UCdc1!oqh2t6?sB2 zZ#k|B+E1**aJ+KtmZEnRY2&4xwnS7}&NM;abm(%K4_7?h@|F8=QLlxry2F28?138e z5@^BCZ^$8=y^SQxclYV6K9set0cmq}(UVkIQ|&T}C5$6{eEw(4O}dc&(Ze*B$Xv-g z*5%d)N<}W=r)H)^JjRgsgc@Ql&z!KU@6dI{{xYJ50tw|OE{j0(8!aC{Y@@P+TK^)| zbgbS+L96TYkoPdw1^l}lUrYC@DRRn@iTjfA)oGH~{GjvJ=kn3lEGS(x_)aGTc z?vl0w^*#Z$3T&tDQJ-aFHstv93ymX7PfJb@oQc-^3;%En71N5hV-QTnOF9gm^RYjZ6A}^ zWZ(5Khr2XlpY}Fm&5rbf$=1}?iw6EZS<{ob3$})(aQ8Qr$HwH`GKGUarl| zce*Q3(EU)Fl|3zAtnY%2aM|>qmWvp?u%paI>b>537JiWe*<_h_FQyI;rZkpa%a0$- z#Vk-+7&^6V%XWr&vp2Sgw>?bIz6k;2yJi3q15D`)cR`nEhQr&1lJa;_C=p^?Nz-o| zOOhF+v^0tzfuO8Q4>j7b;|uRM-LF>{GS~1r!k=;a59D2D%Na{9b>^=?Sf5bv?zHqC zZ2EjA!E%-us@B?178EghVJBI>1Hzi4I^CKO{<@*o|Ew=5PC_1q+7^o<=Jtn)#nm%} ztL4W5#ombmnP*|9Jp<t674!U^2$a|&?Xjhy6*1w8 zNYFl|cbQZvepktG98P!Cuc9!^T3}1vq9TrZHVPc|Ue_)5nqGjyNGdcaXC_V1-~j+S zBN{cqDQr|`xTf9h(xUBwdk64_`7IU4RA;xaEkTSuuS}a;A>Z*LYY02&w%c5^8~>es z);3il;O*!A8=$4?m(I0K$KyZo$PfeI@mLqE^;Zr_M`*d0kj~fDo}}lUCsG*%qFZ=* zl*I$hT@ftt*c$Oy1pk!zNfy<~m$w!^ZRQfCdzpO0mz$~+u?k{qF)G?N(R}5^yMIY` zPEh`oqAu+H;A76Id+(#$+ZrbRyGgiNgxKR;ZNb0zY>ryXyg~2tyIIt)rMH<_JGG<; zy{F9d`YpFO4afXh4KCo8C>FsmiONgrp_|pwI0(w1F7@%~GODlP`W1>BUTMoNvSi3D zsDVoe+L%QpFCOp00U<`ul|(c09HV2GmF9<~)(kq7ag2}wjF@I6YEGIG)Bn!}VB5tM zZ|{)OJ4sn$)S9Bou%t8C)`g=~uk_e*u>9V_Z~;+SsnDI9nd5mlPn=^z3Io)wtdu1$ zW%=@jMaAQNuptyb?x|&m26;+>G$;M!_w=gKL=atZSKDeP)KNhykyN0XnbSy<+Y#`yLA_ru zgw!I5`NLMs5|4m9|GmpmcjzyB4})&|*1WIk11*^}hy09l1-W>bdwcXJ+S@@7q@i~; zbh{prWbF0k>q3t{aWY)I9rOUyRU(2d5x=2u6W-Nq9&jHoPnK4JT}Dt>n(~5DXuw&J z*nV%^JlMQHs^BonkAdTb`Vb2f@2u?{h(4AdqX`Z`0K?`#UatM_hDP|YeuLRC3* zWR05cyQ;NvZ0-H2Tp{x3BeU%`QYc0b|5o0w|wH(0TqxA(t%c=f#8TwdnH@}=t< z(IPVYZyjAr>nxdc19YR!*YGf0?^(l}?=RqsEyosHp_y~p_5<^2zCNZIbeBwYEYtM0 z&qz$;5me!ob-V6+!0tC_?SISVuwnzgT@MeW`gI+pfp}U#DmDvFR>!Eo^kr!XNjtxVWa2 zWvd*v0{HArCPe+iC>f?H|(H zR-~cPbL+Ed5v8zr9~!1>$2rGF>FVX3?_^)wP12q^cHT&yeTK|UJLRqm{eJ}kD7 zaV)jx2e{awzi{93%6@*(9K(7LzJu-LNd?4)q!J;!Q4I6Rwqr!Kh^1_{Gp>>nXWut5 zvSU8UpR)Tmw~POZbpw9y&O!&nb{dZlQf$Es8fJt8%{7lqk`|!K2cWn6`i0ea*NLA> zGB4s&S6*6gY2JM|mwi72N*V2ZS`5Mv);n_B>1+dnb&Xe>m=4j24djO#~sB-@)1pCt$3}TAMA6y!X`|9(4j*a_rJsZPek{8quf6stngYwqt``3L*Gh})*2wO*0Tq?ntW((>7o+`B zxA^Fhiha$r3Gd_)HePB)ABF$siw4$7)E*%9kJ|z^zXBwjG%PVcj6Az#rMscbB%qdc z!flBt#_y70JAb{cVjG}9{7y$COoX+x?_1GqHi`REM7!hl&V2GgrQ?sDIQIvCB=_Wc z7;(m>$J=}1vbeB~=Az|q8ektB4?cSxZ#S%{wL5mcK4P|zkIX7fo`d+e=1N8>B3=hv zMpnN$Xf6yGzj}%fR2&c{RL4b-xagQJR;NR>hT=w<;xP8Y(hul|Hpf4&Li{*}q=17M zcs2X@{rP|ptV_8={^*;&HHIQbreY{Q0qtbnbmS|a7S8;^dvD{u*1oc0y8gM&oIR{F z;9w`gPnW#;)Q<)u!qpquaDKnv2)kD6|2b$>yy)Hd85kJiq-Ca@qr;y!w(%P-2pF8ib%tv<(t{!psJA{tPutklB{im-ODF3#kN_d!F)qcS16 zgAio;388J$dy%Kj0@-UIbVTEu(r9%sFgGzwxbJ(QAjaq6=OUk=EmMYg(yqKmWBq$!f~6zmxx<4?T4 zOrKTd2LaSEnADMN*KGkEMiCto*uG+dI+ksK^g+m8O^mIuK6vD}-%_b@UVVXr#&9Cz zQCAMplHMFtQrOqn-QAsJ5c#+2HFzUrheD5xU(yN%9%UDDFR{f#u5G)OEYG{K$3C8% zgWzxEQnne}y$~s@X6dLHhJ-J-ZhUCi1DUk|pm{X%}eYb5>mcu_9h^Aljoh1IXQt-_{|FX)l?cdV~PmoPSgRz7~9mUVbFb zA*zF=zw+!xtOMk7vD4pKQUZu&S{>}yX_v33lV%sl-2CrNwbMR3BlU9yiXgRaSQUgg zYy)=j{<+?dI^E)p>!k>oj0TJ8K9pQQC!qS_eXadggT%%x`V{|V(g6Yw;wLS_F0lM~ z9X1dZ1N<*1gd7?>M*6QzeW46(QF$c!Rj?(X8=q-NFE_+V67Tanbp!REt;jx7_eY84 z`@grd3mZRdt1d`glvk(caTS2>^>Wb6kI@xgvv~IFP^Wg^(^HnW1$r!w1DWcF;uuI8 z!DLl*yKe0;cmty!cmmYP7Fd^vB5+HL>{p7i=xFPWyrY zE^Q$(mp#{MoWf#=o^z!X#(I)764DzI%uObvbiZ?mgVxqr zXO~Mf4g~b(r;Hb(p^ORnjr%CZ_x$#wP)PCOb181wDMm+upvUWf1)d`+Fbuo5Eo6~T zvT7Ki^OA41=%&|#32jW0jh(jhUG?By!-kVu&a@c%5d>|FNsF=+t3Z$(iNd71fz<$Mui_h4 zIzSu2ESjcZxtd-Kc#F?A_YZ`SL98_ku7=R5hO~FlfT`yZi4N;IE@6iFL?+&OA0?sW zAnAbfr5fUgd1u3Rh8@Ks6kU|q@j2>3#P>vDomN_xX`r5|gWG@RN9$FTdK0rBplnor zt!Vc%3=LuV?f5F84C;&H3GZnb>z}zG-MKCH7GdJvpDgDUw4~3n^54&~bx~e{V%N>P z$xslR}NNEXh7}! zT%8qAl4NLHV|N0?Ln|$D&GWz~ag`wpQ}eI{!tfY`0gb%p4&Sw~0Kz<+?Bg#4EC{?Q z)DJ#Pk?*P(XbH^&LYh}Wa?j9Wm?GAVvdeDC@&fHPau7_-8@KUXwtw*aw7nrypZ>2h zX|$Oj+Ew@l&CG<}E-bCzD}ns<-XmXbXyEtby8o;8FXePTE0teJ()Damg(>Kvk8h^R z7z~Dad$0xE(Dp9$Q&>oQVHNX3hegYxUN1b+MHX;|3@KbJo zBBpRsvvII~zqzBxYkS``<3%9$_*>eBK4$&H&C}H0nnL_k2eTFf!0CB|;ti4O%DJZOu zEcsU01j$CQEz=+W%LBkci5~eETlT6d<~bPjG>2PTFs_~`7J<67!B`y=wquRoz3JT@ zdGg*yp4IRx=33O+e}9sy+G_@{);8c|0bhB7p7lf5LF$<|?BG`^>WN~X?BeQe1!$-z zv_=d;gbvs)+o!ntz+2#Sm7nn#L9%ASW+O{bQ6z5qM39h7aD#F6ZN96R@8|Uz^|`+F zR+gA9rFe|=alUAm%&uF6tmil0!?8Q}?erhn9%^==0^I@3Yg9HJ|9BwQrI&lZqOeZ1 zq1vM71$9E_2;g~6lA>On8=~7pP@+ytX<>u%)Yq-hnJmgH-(2qAMJdPW_IA}f;9n1% z4jwQ=SW&-M30cFa#ZmR(pX#T+V}Cy<9QYIqIuM>_NMOBxUVadA ztt$5=uH`>tbkjPyG-fqGb~k}xF+6X%we?L$Q0CzcLoiv4&9LaY40Lb`JsH8{GKMZH zU_FztC<2a%_TS01fJ!nk#;@RFC7QS1%R8Hdl59qeb+sjfUlDD2XSuvmMaJz=+W!V2 zvX14Qc_Mr`t5IX>pAQ6f43C!SX0tLjxGg774y`9N2?zB1_Cu;W=I{up@&0+P59W^M z@R(`#z172Bvw7{Jo3_C2L2prAn@yr;!V?;JZ_}xpL|gnwkh8!TkRT$4`p%qOxQvk1 zIO#e#Vx}0lnahU%AsN$Wpb~JsY}|`^p&-|`}P9{$1^qK zfzkk1!Or`GuWs&`DW5!DA6-+Q!h>1GVdOCmk};q#zvNKV{Az|v zE7-{WrfQnCuY^02xy@`U(;Ba`9T0csQTMONkuGXa$qB8Vt5-e;ettwYT1`Sw1cH@w z6|-)^f6J3ub(Fv-3Mb9pNh{e*2GG;mi`NI_=#km zpLM-C`X2%fZN(RX;HLWzD2K0^zT4Clj59?lcHKLG%anVilY>fbzfe%?oYYWOfuPi)0t+r8*CRzkahn zxpBC6b+$y)X_tAulPZP%lYgbx*YoeQ4zwr(Cfe37N_ggg?wq8Ca`XM;v*8X49V$VS z_&7kMOHCtPM^oEA2gtl+RxAdCf_|_FMa;E_Nz@fR%@-9!^hZ$ln<$>Y{b$&Npw6&} zW?1;1A_k$bR?H?shaQ*SxjrDw?H_`Y-kCOe>Kfh`@mR=gwxC<7C-$pM#o;ZCbq98R z&fv5)b%nj72f=srambDXr39&%R$TKXbl%zBR?mN*q~RBcnJYYg8Mm@_1_; zvqj;h`Ek4G{PMPz>8+*^Y}qADIG;AP?38vGp^VdYX9&R|z-(oZbQ()qK>YN>aFZF6)iD_QLz0$SO^p#(bGFedvD+^WES-1EKy(C#m{zPt5d{xl|^fWjcF#&{;eJ6ql8C~_T_rC9(*aGR}XhMd8gSNxt>)vTo zdAao@Qu4?QMCB$kq0scluYi+NEpHyT#m35;v0oGNaxsOwNK??3O9D%gHh$9YZp^5L zbFIn|1ch5bXfSTyBIa{uj7*-Z~6Dm1uR6+Q<34Fd!gCi^RWN%Lun+oO%Z#2sM zJ`%qK4R18|_tVB4@N3X8hmMC%$56bHZF-Iq-&o~7e_ba&_l%MVaj@B?2f9nB*l)bH z?+BBw9Q>*CAXI*91Z73NUf>(cq>?)#*+GV?(nXGUs@S6CPaxoK5F+3bne_m8gMeHb zFtsN1uDh!8+8YG^xHq`h^x8qg;irj+$En!`6GCg73~Z9kWt!+(7UbEa0910OIIVwG z-{^v758bUGB}Pr_UsM=>7yniFKui42Hy^9Ck{JscBL1Myu6EFJcpRB&e)uz@06fJb zG+QGwUT*Vx(XkB>W>$G#9iugm9eI_T>2KRq8XHq`>vUMI|6*9Fl|a=YS+*pzNJhiG zX6GIN8W-4i^RYHr=whnh{+0lJy57OxnTTi}srd5UJ;n9FIvB}K=TVRyKWKgeh@|Jt zkV%7e)@sgvDzvRce9Pb>VzLaowZ?5Xlf!(PsvJx8JWbDxP3Tk)wQ|*plCYtJC$Uqy z*y)w4@o~J-8WsIAXtd7$w})EC6b!iit$`N`gftE~uVmBxE&OY5e~^xupUKV)2myl; zPniVt`o7mI4P=ok%YWmbktF(qNw(&kHrwIY&_|d4pqWrt%7i9oPsQAJY?z{nAZGxs zWEjs zZYi;3v2Yx4CG_hun#@>o2kQ*)^goC3Xv$4w3>Q^)t%q#bxLhZ)6~5p00Sdu;T%Rkf zqo3CTTcK^_={Z@1sEy0atWS_z&l?^J=&98=UB!kJ_aNzo?Tk4-j8J@c1X5w>1z|Vs zcOUJ!cFJHlaLT}nJGsoHErcT_q#J1yi&{{rC#w87U)^xOEQtH#N6!AUP8QG9jkw() zpOZG>=Vj$au#Q3+Lj=?wHT@=5r!}EJ8UvzlI~2)ZTPp*|?k))L_gA||Ax}}B9|Ll^ zm<+ncNJ{y*^cBC|%pU$;({xkf8Gd|Y`;`N)j6e|x19gKuUlV0s z2!lca-xfLzSMEDN3h*+F5(Mx#)kDYB&SNC7T2U=BmIp4<1IiHMz6r>fo>_Kz7zamg z{j`1caz@t^v|Tj%gUbZs?^GyyKm|f*_1Pq>l|urWrGhd8;0+?Ft6B?>Yt$ z#;`d4W`@i||M=@W+r0i-i$P1B`6Y*CkWR#QlF!kp7E}gCoI0Uj^uSX+?xhclz4)xg zC~zh6p)eGlxZRBtCzl^;aip3sWR*|>ud(=@8C8fxk|u^INSFrK-&B-KiE5JglOf^x zbM5tnz8SkjqEARIs1dC-P}zj1KbyV`x*lM5EhbO*YB?0bxGva8i4_UKU=kt2W6b5IOLG)yuE2YWN3UB( z4>^zIQh3#I&mrOJtLp(^f^98XCS!kV(|j=s}nrGqb|fq;&}Mx-0kb%OgMWtD@s z>Oxh=h8{otdw7!q8GX%cLdM(D(s3*U6*%h%*ip-gS(DaIns zDS9PP3F@Zxq+sZl?2ohl#D3F#T-{VStb>8D?75tmD7LMEjf&=AL9PAX-qxNOU>l&c z^oNh#@9iH`WE!jB@@+k@w~q^es9l|*u<$#X!hjQ(ceI+@kP~i|&%6!;_<+xsC80w| zo6+t$Cu+F9_YH_Xp+KZ|OtLI$HLjjV{V-IF_^?DzuICHe!*u8w+?9Gh z4u0o((=7V%0g7vVyOi=1M318qwYF$RDAqx-$A-`!k`b*;v@q_HMrI%8_gh5YP)?-E z3NNf5Li>Zi9V8xxbiRq&f5XX&L0QNv7jYRw+>8*Cv&%ZOl{U2f5nVn9^s(_P`@!8? z-!p$l81xq^xog?;ee@P-?C^U!r^_rKkP{Y~cyW8Z0tUtOK?kS)`Q$K)Jn+jKZm(AB zVy$YCgZiDdYA|7-fD2*}F@)`VZc3zg(XU_V1!SaPr&hZa+In(hoDh)!88jdfY(Am3 zJ#?O(&v%dc3~Tri`Fr;a_eLFs;8axfP-PDt#12)zS!;VU#i>#xB78QD$2CL{fG|j< zG4q~Qh{s3GMdSe+z&VNC7nK#Ov4G5$y$_2l&-h~f>h3V&h$yJ0nRSVfK z^S$)7NwZ`uV@My1f#ea%tQX4z-7UC%q&{u#*F>E7$qYgk&6iWiltiH z5nT;gv7{RL{iIVzT<;dHXWD*on5Nt7^QLZxZX|{qjciehAL5%+b+;QP!cM~j%JKtY z{|%7cB0}LC)YW^0?nCJ^#p&`PwZ>aC-M&mS*PgH7V$Vh*`+e78e=N9rdqa^i8qv5+0DSQ;V>7d;RVIhVq zNn0H;$LQds4?u=RHhMxBHNu6%e5dr4_i38e`b>cGeHEF_@3&|M-!r;@Re=YiWg**? z%~96Yb04ntM(L6S^P_-uGH4ta9{p8H6GFB?%VX8R(HRU%$=v#P2>t5$&Pmv@&Y&(zFap;ftVNVRC1+ka z-apOdJEZkq21@0IjEzr0yJvqNfD%sGQsI-Kwyxs-hOzx~K!9i$Uh(rwd`qDumGuEE z;45}#S8UA2OqZVD1bOh!scSpmYa=cDs@-NV_u*X1bOC~C!%f17&5}jM>3(#7pftuv zv)2CNCpb`kN1nNmhieE^INCP|@Q7V^TI9=?46=E_01_<2;bO0_aK>@Ip10@hav@x_ zFkR|%k)e^~VA4ry?F|*W;>?V;6qsXYP>p03bm|nQG6G!fC8AyCvH`2x4Z4c!aLFaV z$}tdDjQYs1{KAmF{$#TvC-NE62M%W!b5MBpMaf~we2hb|G4(%Ack^nhI$z}5)#*a4 zKnA-7%O+7*)>ap_Pip@ET!1<`o^|&QXIhG&>BC#U=7!rXPTZF6)k=s0IGs8cZl4DT z@N@)B>|o9kvevvfvz!y8X&_$FdIfWEYLbT;{+&q&%}?SBsUakEN**-z!rou%%=HF( zvA<9!NQqp2RpTI0wQm9VMwaH^1s@qU9e5_ZxK&@*5};=26)NMUyZ%wjMzh5k2#s?w z?rNIG7_{52!St0U-N44^SBL)YLZWFX(n(nzbK<7`rarK)!}H#a4)H||YmHNU*R&%v z6cznag|MQXqSdQ~nC-a=7>P6GQZq&1$=~VHVbk?0c5D^pm0*5+q{yJpWpymQxu5p9 zqYIv64=62^KKLPb-cCwM+!~QO{+Q_pQ$v(t`KI(Vr7yuY!sX2D2T9PMv{!*r=NYfUjkIssG zJo$oQ6V?0hS#0a$6sdKuwIgRr8cY^kQvXPJWDi8qn>y$dx{Ng`XN6;`ES+8qDbfNM zi)*X&Q;11iPevgEmN5^A0`Tc8u zo$6dg?gQt0o_*gq5u}8L7jqm}>P3V}d2sR}QwN)h(1~@xh~gZ2srlaFr`JqD+adbI zBoR>x#)b1siT%+A(9)EBHMZEsKq3Y)pMtD^d0S}YrwwP67`UFMmCMiX$ z3?{=qi8yc&7hpLr8a++1!E2`_;!0#RgA%s?&qX-^+iF}rP}c9p%kP9I9M^N zEjrQa?;1Lwa^N#4m<)OiUN4(Sef!7;)%IUtlF_w_{IH!5zDDS|ub?Dw@@`#0WopjygSCf%X z)_)~nZ)xX{hTE6OVY;&C_xkHlk5k#+)C|n6p?Y8js3cT zqki5=MvD2tWR|mLU+1z@*BH)SrA>o`eo8bXp`u~)Oew=gL`n_lp%Bmnj3TLQIp``- z?gx$mkG?_+z_?8+j;Z#-wuQ-}8mgP5sI9rqBAJ(`341rHbmLPBiidP8NBY7fp(;Ns;YGu1uE~_9@3hZiF6jK8V)<4SlGzxDrK}D_A-*cLTNf!Sxor)4> z`Sh#8Y7n|&zSGw4;S0$?Tddiax4z)_9%O+jSG^X+ zCHZPimzh>BzE74HUfvJ`O(SSeNkyREHcVslUR0a|A?#`I_B978vVOYee2uOz;GPHUF>))<11OhxiW)onJiR}O@>Y0GByq$ls`p|tk^F> zoQ|BhKgwnq2`@I`A5x>o(1165}k_I;6{Dkf6gsEht|LdAYp?EKU5_>9ca@OI^#a1C@p^k@k zkXTIq9Nx4AmG_$Ozm0|q=OGQXJXQ;%khSaw>+4R^xc`r+b8wHVjrw)a*k)s+v28ZC zF|pewnK(@*c4OPNZ8f%?#x~Bp-*?V+{)2h0J=fmPTI>GZOOP6cv?9g}Hdom@B&4W7 ziLw1(n6R;yQr9?>l0In>bF2=yG5)ga!M7*N3Pix z$=i-uHo*v~ek~qYAN+Od1t0IrK?1esPs-p{$e%ye@DBcrg3ivP6dt$md}jI`y8fo+ zPKtdoq533cO(J-LY1l(<38N#Pf(7!ZrV8bV4{nPfVQv>((Tgui`_sfY!l)0h^@mR; z+vYJ}a3OGa%-Qu(VlU$~q(-3%PBA<&UgwTP8udc@)<#$%0ZnkNOJBh}G^t!jzl1Wcn!;JJt(?I?#fju+#i` zo8J?1>nND)-Ie(E5)JxCu+FjwZm&P0QJesjzqrTVQ!@UjS-HcVP7E;av|QMbXn-Nes);gdZm5iuACOwBp zE`bk^F~%iB|MsF&?YX#HPFo*JUh~}K~G1I1+}bei6V98K3q0meHiTrXwdw1HLd&j5--bZWJ*T}LG%6EbQc2rc{I zFM-uzs2cy&;tD@kep1b=fN#;Rs4~auAaCF0r__2%2RlxRN)l^-8!6H+ zarrdNd*?uSKU$zd-nOImwsIdE8tHo|*NC8Nu1l|XuN7IGaqU8><7WbF?#U5qATBY( z^^cV5{9N`n7AhccjU3uX@q7&9?nRC$3dQi4=*|2unyVNF$Igy!< zV9*Qfmq;Ql8=mRG@gex~h?gHynP<2Z)qTsJeMb;icj@{Fi{5uC0j%u4@`9J4SYy42 zM?{C=VZR_db@CbTRD;Z7eG$`wjv*g~aXyW9G7;Fg#;noBNMlMV<>gV@TuhLph@bg3 zvl(@t|LVL2CCz<-k7GHEW#62-$+T$*IO$vZnJ@OEI9%L%v5Lq?=Gc4*YYNE~{yme; zTb7^LTt@yVEaC)d>#kCF?r1PmunsjOUwIDqY6yy``s1S^LpA@S5xBEnjW#){bW5d< zZsGz=-qlkLoI-3N1Fu&4(t*HeO2TaoUy5z26da4%W4g$LGs2#(9?;Iyyy;nu?t*{= zoBYZ)MY9$YOG~Kh=3$HeIC=;ro4)zoUh;S@D(O#=Xp)$HlUN;3wU2WIg8%?qV9`NT zr$-T2Oq_}kue=(8$n&SZM#>h-<@LZ6EIUF!FieQkb0PbKMyBafQ8bKrtJi#%&1!|z zXc=qtz7jGigvZ$Zyc34oxZccV^NFqd8^0-dY^|m)q%#Gn=|+VQA93!pv088?tYTJF zvhF#WsMHro%J8AY&MBUTGN#k(<)xB(iqc{%*{hiNkMn<3y+FRmWT<|$tXTM>g9yz*tw1>{ry zV1CmgA_uR1roRkM1UFqUNfdE&WyLXQ4Ria_EhB=q9S2d3NaDHV0jqoz=1CFAlV={( zf`aK6I4dtYKZ573g8N3tB*OEj(_|8U2)%Aa{n@bX-%cQfG9Xw5*Bj&tl&Z7U9l+pU za`}J4w&7MV+EWv_gSqI?s5NAP{C>f*hjdmu<{bxci(zCcM0P~3d9#_6^fXH6I`6(K zKTeGc>ldh(|*&#ZB=C+en%V!)*SPxruj{RMOjzXDKd#ZC;Ny+2mJfn}DTNBx|JOf6q zz?dpqAH52h_TbyQ;_6SB3b6nzlR zscXPrkrv1JGvKk@KU*jFT5UT+UGkQ>_ziut^OF}kFy_p3^_LmX0=J>SNTuOdFODwO z5N@lorA*>i1XzugCAuiac9e~RSu82K6|=(Yg_wlCP3`qHRu3Z0(v)mkiWH{G7gf@ad zTMNsk2JSIPQJfCJQE)uSf}*~gUQJNMadGo@eO&EvRe$$VRwwsj@kQKGC+Fs6 zdX<~89b=vRMGZt4`x{CSA_7xD3n=2e7pbyS8lFM2UP2m%7a#57@^C2eowx5K?qV*zT zu@|=idQM1>eFh68C`uWlpkeH$*xw94cwyNF`a%68^0(mbhz_+Sk)C3Z-+P;-rr=;v zS@Fn?`XK|rS?o$Scr2*4iL-$x<8D#?U4YDMp(W@!W52L>35qI?*jGM9QLMZ(_pFE4 zSDO}yOO2|4?C_U{r6Xz0F^N{SEt2xsSWWNH?bkZ9IKn@a=v1UcFpa#iz1L*Qc!l7J zz9J({aO7MZIJ+D`F?nup1MJ;5%boU0Tp(iU*9CF?_cW6tOVQ*TV494ZZweyi5;{|x zC%`Y2A_lMfehMyS{o4RZc0?kQTt-3axHS54mDi-PHu)lHVEvm6MPWp{jOJt3NU#77 z8@BFFPV<`G%6Thf-8E<4%uooboxptlpx{#|Z(YC8D-i?|npV&n2jZIX>2KJTw~%fs zu3kgviWVjqpE#ZWXrZwwoQc#f2ET_p-KykHwjgpMMk($sMzvQ*CW&+5ijE zaSY4-wbcXF)~!3YBWE@;gf;nD9ETX-rIjLI855EimZvW_{Q|SpLq4Ql{E}<`<&PAD z;3<{jR3*8hEPbwI5aMt~RgX-=HHTIYE<|~wn1=-h(FK|)QZV{4UBEZdiR z-s6eGQ1MFk%%g#q?08oN#l=GZ2{<;D63Jh}aP~tEdj8_!D3euE$5yGK%?h^_WUmmo zD-Wf%eX0w2gF3OdO5YK(P4EZUA4Sm%p%SsQIXQHzE*;7$Oi}@^xR}8emx3OQJ4(&E zfk7LKHgnB;k>B`ZVUth0$xg@T1hHY-(SHZcmT`+vQFlrY0a%L4JV+iau!$x0-mey8 zCqM#6pQsg6AYEp#{5E`yAr*)|nAAM{fJ%rta0@SyZ&`M~&qm%MMm^mZ;d4Umn*vsL zUi%|py5Yj07*YILpMNsc$2zN8OC&*E(mX0QlOa7Nz(t_J(~==wA?|E2Z#z70l7Uyx zF*1U#rn?Zxq3WKTd-4-YSc^CKyga;#CXb3QpZ(G;(o|77;lqBY((parm^$ThKMA6#x(98s4H4#J!Zd>QOF z`BPG9fI1C}h6Mg5ayEb`Iik32YJonK=N80>##UkA2}7C zNFiko-M-Q5$2M@0+m1PoAPzO;;>5-Un^5TKT6*RBN*w_MA14CwqR1ih8>9AR)P!dzE+EhbI-Ei)v_3O^NAS6ow{%8 zE^R7`2_mV@=Wr*pOlV1qpm&r=G&dFYCJKOg@VK%6mh~ZWv(Pa>2E0-G3Z)K3i)g2J zG#f7!sC9WGU6FkvlXz93pQ}{9cY-$zgME+DCOHK8FR-iSJFt2rO^SwWX2(Ss_D69k zx^QZ#lAA=*ZPyZJIz}q8-Iq(2!XG#N&IE=eTUE4K$?r~nvFIO(n*aUd47&cc2^@jh z1joT-q{BqR{{jktrO`9%RkAjCckAKXzi=z0e+Lw#Us^HBkT9nuooAIM+4j+to=D>| zt~ctXXTXoec@(1H42xpm7N?3p*F1e4BLxt>Hx)jS$;Qq}B;_V(9s`;<^gnXk|Knez zF%8f|rSnISZAR31?N4+08R^fEFgRl-e#f4HizPL;Gfb_pLhO&@Ei9NExq&bepgi=V zG;|~HxVa_k6UF!a-&kDgsm1N9#rXN7?Csx;-OKQ6^T}Rb0X2SQ0}bP+BBx10g_~=o zr1(J7f9ee|p87qX1NZ;dn(W(ZtmU4;H?QHu7J17f1%j-(-%%9$7wS8izt@*1mg$z) z#gVSXIYZzqrTWH#o+N68xE8-2X3dK#(IZ$#HbYU?KU_d7C}=| z)gf?8s3b|5((>&RAwN;^T0#XACAkf+j&_lxJ^OwR(joAXDMZO z>b=a~uycj9^S9UDfr_#r+LgSy{`{@XVxZV_?5b|cJ{m*pPZ z2mmFAplrS7_cmwCf!Bbg9(kG!aw7R2nQFeDZi~qUUui#w`d5qVI}36Mh_~o68L1`_u9|KJ zND0uFTPw!Q^sX$+4jB~E@_^ZyG*y}Fc!~p&V_|kZ6!E$dcmyd5-ul|b&ip5nTKhWb z(5tzbQ*bf6ok?zO(~L8Lp6b#y5-Qa>s7TJWH@F&R<}Kcpcm7wJ)M){#;yq*ZB$Xn5 zaqI#`|SI365D+Fk~9d6v6K>J$semBL}6PH4PjX6*mhJskTCTQVAwBfxoM zDXMeW6S64zH43@!r&N(|;~MvsWh8Q+cHbJ($`|fJ>wg#0bcOufaT5OfDazpm7E)dA z!DU{BY0Vq3p+xNlfK~1Oaj`Qm{p%S*?m<}G^JoRq%T5@0EUPF@f;jBy=sWwJM9R1T zP`D)4Lua!hi1A614lxFAJleT@gYETQ?R^Pu-`Vv$6ry0n)7uBjuNO37RhQHDBuzc= z)ZZ)q{yG}mvOSl|9?j(1D|_Rsw=6E;uQ12GI02WLfl!(yb?ON~G9Du{2ttsMIt8$* z29g}vAJ*nt3&_$RE_rCYs!soP5M1a#44MI7-!K{5?!(pz9DcwjTKqf8LJGj~|H zqWIi`LU`8Ejeb%6%BGgUjU_W`bxcdnG9qca& zEtOj-s1H4>m1oa!iJAEO)HKk&@%ph@!7E+?rpzI7fwrsPkiH8B$fErLDu}uK9O9%-nDi8~g!!q=Qt{Sc#_=7)>p$$drm(?Q6B&i+T8R zdn1F4v0%>_rSV$WjVb0mXWzb9R)e2a;XGLeS8kKez^-ufdoEZ866RtXdDz(pvW@(n z()wQm&R?xm)sj{9A5<+EZq()IYq6zeYd!T4q{ud{kg=L%e~fYj^_;Ki;sbebYiD%C zH=%oNy%Q!|Wj%a^?15GPbjA&aua4hZ4&Mhc^-oC1xJNF+SSvQM#z(B*y8`2 z&XpN&4o_lwTDW4PyxsV3t`imY-EVvgJJ*Mm)949(6~SD`!;{>+Uy34dT%IyM9J$Zr z8_XtQ!sY8M8VAJGz%fNUh+)(+QpyB#lOV|AdQ-~Q5rQc`hWmber#`>LTu#hd@aJgR znA1Vlsd=8h|IzOXS!fg2@CL5Z>|WHW8saHoS9qCkQI5m-(Iq|y-&Y>{%4Zj5FeF(1 zD&0rCb-xbF!;PN{Db^xa9^wbh4xOL&LQ?1{Qb%*R9GX#feT%{L@RN1+7`>&g_p(%MFFm9NBY##ePzXb zgIDq9RYBzhF1X3*Qw%$LZ(G$>A!u$k`iaeA}?b_xW+s!~%YQk}#o| zm||<7swePfpseakqB=H^kPMh}ShkMzk-9&^#u|RgV1$!AE~s1{T3N@o*tD2$KkVHz;@K_=9L^1J;6KD};d}BW< z8MWfpxEdu}fB&&1L`E~(GAl8%ooh9nj6u=Bo7GiieN}_|CG_4DweM$$`)G+w%kbC) zC8-1u9u2p^o!2%OWzD`#zo6FBIX=_8x#1#LM9<`A1=ZZs*v!p zP}J~{@L!I!0VXp&i)I>Pyq=nkSD>oxaFzu(Nx7TBeW;=IB5q|zzcHM+Of>_qg(a|( zK>pldvd3w88%yBr-qES`U+Wa*UqClURfPHNG8JxV*++u5~I)^$yF09FBhTZf?=AIwZ`Yy^EEfN&3Ny4Zc7z zF{$UWv#>qsr{ETB9L^`L5J@_2SXHTUEU|gPu z(D;(%3DO4!F_!>=7tku{EkyRC;UdfZoibKTXYO$!R*9}kCH%(6V+leSIA^xd%PwQ; zd3SY^YAUdZh=~ZSM0Irj+{|;Hvc!zGn*|TJg1n5Da>a}746>I#nMB=~F;RfEOcoo< z*?Had>I|hKEq2vUSh0$`c%RC8XvFXRbzIfW%U?TTb=;VXVlFLyS1!FfOX^+JL?Gf$ zeCUG7O8X^tm}^PSr80_1eNy)#z5yhE7Dmbqe&a%ecoazqq7&yRFC$czC0MGP-5+-1 zz78_jJ)*e1N)j*I^LCym!kQv^ea0B~S>9z6p}qYldyGwua&hOa*^3qciWm};#H31XB0VS8fnLM7j7tKWY-Hc%hpk_!`MPwDY& zY|`sN?%@1UUR&R6U!|?BP1pqpI2s>kF}4%%QH5rjN*dfg2CjV?a#H%N9~)yQO$o6u zTeWyuIMKO6Sry-ifyb``95hfs`>tU2pEgcvoKjxo;{8i<57G?3X1tN8&Dtc>$`U!D zH;Kzp$nAerhR!5pPy7mKH{KN{j;-!LJ2!;$7S_O3?(NY#&pB`_H+Yjt_fD^RW@ zH~o{Q?p`(Vpe((qM-(hXql&erGdx>SJT>x?c@Tb76W=Eop!MSS?kbFM^t4RYRh|1Q z3I39qGyB-1{V$QwKNQtj2e=MU-(d8@qVs?@#h;Qp7eKAJQ0G@#*^{iJW%#SulIUw< z2w}1UL4hj0H%70;s{`7BU<3SJ0bfRc@gHJ?gVd)a-+U@41Fu|=)I}56^h=G1T-Tw< z&00(#Di(u3(5e&}BX#K5Z;23NgSi)(^D169YiOcOd+T1%9ex)yLfrFP`4|?M6!Az% zX6`xz-fkrq&l}S!d?)*A;7mrZ+QgdK+lq!m*;>s2nrzW!5?!j;*$5ETs18j`k zsThWBr>4+x#eNh9_n4}us&l|LT#((s4T5ej!VN>g{vrSGHIO@eYH$}~nOa*vI!t<|iu*E_%ODo4$e3gU$m3cXwIG(DDeZ}1P$0KJ$$ITN;Dt9wBgPSI z`dNY6`;-F=dF%uM4O84-cPQ(glLWBTNJ4hppWnN2KWiAzv4N;rO|UxOm;!p|VJw`= zs=N2s^L~tNDiU7m6_F9K9mv4L<+bipC6YQz@kPA-E7M`@OZ91t*3vAwABq0>`I?fg zN@JzuG^4<)CQHVfNZoS_aHbcYafo>*WsFm`#W-1R?@hlfmC3qqX8XOg2(mo zo#9k=qt^+SCF@h9e>m!!bJPT?b_qh)0-=<(`>dj~CaVHqIrLcm$W38{mmr?@h)mTV z(9bl;*sl(vf<*iW`+MC~;=}Zs#k1|jy}O{#5V{lCgcV=A32rw}w5SxANMDkmI;!dh z0nML*p^H~97bwCUJr5-ar(l`sJxjnwQTWpn!YKUE-gpM`CDl(#?#i{C zdjB}F7IDDrQKjAO3g;}i?2HGOohfu4!7oZ%vGJrV9%VN-|13D{+1ShnT})mgLd5W(?X0QU^*vv z6j0uvakK7gE5xcd?Thk%J}~W9knO=6|4?M_j4BPem4?L3U97WH3_!}C*Iee~eUwz3uh{gu~#;^)u; zGsI*kd&kx;{v39?x@bG0t=H1Fx4j+l9T?Aq!0JH%I&bHzoLn*%WO15L`TS-e_<2T7 zK!7_P5mcUTbMIx0RqCx1SD(qfKKG0*N`lq7&APN*P80@vayJ;^2NMz=rJy#iK8!E8 z5=)Gafd)h1KdueuP~dy;J2#el6KkVSAHszH-5_qJ7-au(T=7+lq$iCw-}=Y1B#o~T z6<5v_?&u=yHb28`hq4C~B(755zql&MkT|^<8}fj%+#~$Fs;}XjY%b71)YE5gqVV^x3`i-bW_XByn&%nF(jX=atmg<+{8&=HvA?cSP$LPYF3x;y zFFawf!=#zoz8z(WV85yQ>UB=I_M%-R#@TZNutCmHYBuy6E$ydOHqdM^xxn0tCBLY^ z^M|o8XcEfxeG+$HC96G}!X8bOzW9kze%%9N8U4s*Pnrq8c{;|JU|q<2UbMU zh(@HVFL#iVuJCi|Ru~`TT<|kfw>b-4Z^36?*Np?<*B&R@bz#Pe%Ir%U);l9gji3%X zbmh3ilEK^ax(66rO6PKD69Bjw`JbP_L>i$p?67fVLotJ3^A~zKs{6H>SGA+kH?&_+ zGb2)GQg|fd=0ai(@vOhECE}N?ZNkw$3_$Zf-%`|ft@v=KV{yTocgZNh&QJZ7n^HIJ zlgmbd{_}Q18F26W%V`U%KQL6Sd&7-**8Z!D8$rD? zZe!}Gu`_OB@1-S?6wZV2abqA{?t}}x0cMYp6nH1VeR22GP6lI^ZoPgIiH!|z-ldvdd zIz%87ZfcNZC9Y_&i1;XOAl@E1AKnz~Hkxyg4B4IB-V6GiK9PB&_}Ni^A>C`%$dj_` zJUVai0k9$G138kh1t$_d8cSD!Taj&HP4g^@iKL>=Ob z-w?11X?2iVL!y&we>H`2+N&gDnnCJDQd$@isGiPUrC4NyRxjet~5EIT`M;!1} zMuioWLuxVcm_lT=KPP45S`-!fviSL~bX!F;jk-{)qi131dbJzl=HAH{uy_b?7Yb*8 zy~OD#mPnM>6iliCG_c()d|$!uOY*t4oleygfb{bxwLZTh z#r}e5N%PH;-Q3^gUg=f}LX7J;j(8jn5g*Ollz-A1T;d)DOjr*xg0nsPyds zMPt!pFY-!tef698B6~p{A;sQr9W7NKb&ax6C|&{~ObJ+4CMx?!b&c=MIp7_52&w#M znvS$KA%Z>h^ZVFOyi+}Rt8Xzl>uCQoP%L^@+@D^ba7Hy=9?=#wM1zGruah)H|rYV`3h_@|bW zPyiDpetipESS#}%-08$qJxQ+=BQ{SOopL8i{E%EU|GbZWUO>1DR#PUGp=^vQ^#Y&# zmv3X1`>sK&*Cmj`UH}ZecIF{f;Itg#@}u65D-s9f_orNQD8Wu^yMAOMBHgSv&Jtt= zo_Jg7> zHQ+>%6OP<|0-j0#@X5IF41s4y#cffT_wJ(@$8CiDGyy0Ym+2IP1$W?angI&XvV*h! z5s7#N0_Ouq$IMWq)@1uLr&i1Sc(%EIa0Xt)1FM1)L$`(c@(;cM8ko%NjEZxq>1`>2L=OHkQpxpZp96Omr%M{z)R$vHJwrn;kbWC zbiY-L$z!M?a3&Ym&q8G`J!M(Www05IM= zImYqBN;&sz@-1N=-UzRJkGtUqYPq6N*D?{euF%}33jhr>JR)gR$vQSt2#D_(>)#*6 zPW}D57hYc)N;_j*q55HRUnPzD#OGa{sDGIqjd z)%!zEEspZ1s8l*P9{bB3efDke{3e*+s*BgC`efNz0|=QV(*g0I`xa zEp=xT7wF5@$BWRizY1(5{q}bPpjX}Z>HU4#C+TlC?;l1AlL1W%5D>|~0xZNKX!==O zFp3~s9CfkyG#mmdtf{j-@4muIUHFOx1+UvK6G!o}Bc1y*^^lNqHafL%W(og|&FpAAoxNd8(t=-Kz>yi}e4vKXQst0|~#L5w%)^3$!1r7sXo zh#pR4GdATa$C$AFjlS4PDCKsC&u&qNt`~jfi(7KZE9`<0%>a0d`s?My;YnL{j84-P zm|l&d{}D2Qx@B7|yU;IhF!K-EeuY9zb*BF z3$4TEn37uJgx7$40E+gD1@yTwOWpOU@T}Oes0sQel5}m9;H! z;V~-pp$q{KtAhpTqTr=<6d1Aq)3?oBJa~nXt7!y<=07qoHmL{}I`^hgh2!Xr(No=& zQchr^tz6#*qVp%~Qm;(*azXHeFN2>yI?}^=xL1?r2MS`;9 z4gVsiqq6YKE_FhAyH&(kmFyaWIZyZO#@9qqSkuPLtPTO(O}XBTtbyyjMyl)Bp)vYv zlVkrrw&K!&=^YUM>83ijbQ9GqzljePX5fC5jsvG7DLJe7juEF|BQOe57kxV_EzHMY zWLvP;YdwdZ$j||V!~xAthf4=#K$Hd%P~qxCd*oSbOIm*dMVdH`nQ^wgp59p<%6ZxN ziMsn$K@})GVz$ZSsr<4nLu4^bsZ9M%@Hn3FH0H_oR@q&6PyQh;e$CvK{&?@tG}OY< z+igZgE#*hK$xH`JktJ%rn}Yr1w*FT&`Gv&Ch}f@qmqV7p?t!eZpOfPa_x`(v1m4hS zJSN;CMs5-um6I)q)}@J{Nb2BOIqUv^^rJx9?HP!{;R4?Q^J)zb>~{N#;=FK0z9SYR97-9}nm@;q{rF6jRoQaC;l@*Rw7=Nm zVz?m##Z+?-W?=uO@tbPS^m)*>{GkukhQCD5Mdh}rE5KZMN|PT~H)3Lko$RMJ~ko)Kv0$F)E!me=4YDPt=tT^ba;6q1)@k6|jf2W<5 z0Ipzz+udO}q%4id*z+h*|Bsbn7^OWEN8E915ns;HkyBw46s@6U0%zE$F>!rW_Q*rRf z4Z7WB_BLBApx3h&rpB8heoCv6M>p_Wb953erB_X3?#x=uZr8BkO5Co1&&>C!vzyj^ z+~zvw7JKOpLkcF9_g4jxbP@Aar(4VK+5Z%xHe4(OQ(D#;NwHTxeo+)9JlWONVo#{; zU^1dypwr)tQnzL zhTxG1Ha>#G>n7$37*9-Cfec%QQ85MDL&GFrFVf^eR*YN~{H6JfYFeA|ktZQDLdk() zLHI^vBs|ow^CT)y8G5s=Vc-fxPN9u7&fe!Z55Fr)IFm=c;uajAX^_gp>}+v|7Uy!C}YYl8)ZtPBrz zJXe)^8g#L&YUl0mYofK0S@ZW`4ajVfM`>!=;^;Pk*=7eT#$d+nyCWmBgVKysw27c--3#IhO-usrxuI+pUNj=Fj?y1qyWSD$_o9jrr{QTN~;w6|t&AthmNRm5N?8&I2v;C(pXEc%BpJ_B0A4tY) zTc8YCCUjC%z=kT&*IC=rfKE+q^YxU}3C&a&z=p{zNW}8`@3h4VG7yVLEGQ-pJ}k*w zlvzu>$gM9BL@u|S@?vqiGRtkb>`|fFwC-6T_ zt|ki)+%F!YI93k1X!)ocEiDZC)MIsjXr8_OIcN6wXX1a)=uJ*R$Mo-$~_+iZ;&Ak&^oX3wE9ZDWz!Ba>opI|au` zxC1*1UN_<4zpcrB>==qYY^SIT)k^IJGuOTU?xtlDr1SlxT(ObpW?O){e=vcz@jn>- zA!lE_rfpouYW|k8h0UzzEIl?ozkJD-^}FbtVb5mxHZ0SC-7s^4n$jC5SBvP2zIY%V z9j$`(bc5-lbsSdpaqEuLYdhk*c#l$W@DHw)pK<#L5U=-_gDi@&o^K`U^TEv3+#)+Ljk#>q$55>mP_ zBnYVmC&V}xMn})3%b~-5piIHE> zqp2l0^_F2s#wV&HuqV$eDM7LXLJZW@4J-UZw)Sioe$T*fXgQaD&QF2X=wpIGq z2kXy2ebWVeZVFPyH}M&c;UphAzNx*}s986!0&}7&@-R*q$5eEc5n?;aj@FKr)F=>``6{?$|W`Huwu1{d7K=pW_KK}0!H4E<&sT7_nF zbiK`*_)VSQcdvK^kO9NVUTmJbkEWL})wyVPIDi9d)vdciFf=N(W5};wE{mvI<_{k4ZLl_e zML;V03}fX11W!&Wz_oRyL(u1EE;U={=}AI1i1qEZY`e~3ywx>8*@YCHn5%reznNW7 zTW(B~gXg7{u`LQ>*zr9(;hTCL=dU4TG_3^f1#-cl1XBLp^AQBJ=+9qIk<2HK7xiQn zd>tBq6K%;MA9jebz~IQESg3!Yu|x6dhm{MzF5efRV%HGt>W%2j4}RRbyN*W7WF-ZX zRw^r=iwTFl|F6jXKUZSA(YgjSQ!<`nNBi2Zevz25u_=9BR` zX7w0{6oIU%1w7$nQY8X-VS$5B2qJrfH+o2j zei`|tPji2uff_VZ1QIy`+M4gXMg6Qy@|)Gp8=tY<tEo;*=eKO%D_(NFt+5*-Z}9Nz9-U!m~a(`4covw_|n~hTFr^{@7#^oq(U|CIy|i($Cl>r^B8SmvJ(;OFYTB)=kiX z8HJ=Z*yboSQg^dGiJC-Z49CGoLm?07A>z8_qwl{@B^in_5|sehoeuUdtMu~`jh;Wl z77q%u_Pzd;8LfG<8!~Diy1yd3oq=G)aOWDb)B4Zj-LazXm(F81be5nqz8PEP1xy}U z9G0}rYLLM^%#{$szle*Y$2aA>#xQyfE=#oJk>Zv1`Zw3_t$m<`t?S!4#>!5#ZF?(J zmShgL!?lwK#SwW(UjMPhe@DOw=atbr1+0m;#1K+Ege7Q|REXQ+26KmAfU`QC1RIn| zOpgjN=G!{{D!iNlZ>3oi|E?Cl)`6Aa1?9}qP`yG{KSnNZvs+F4KGwRp>;y}{frAdT z3d8A2@Bd+*ogY0*h*@gt;!vxa8;;y)NgQ$!eh1fI2i&Gj8PYyT;bd?Rr90(SuOpzWlBE z820{n8jCM4qy8eegI6cwS%8OlRCaPd13z+y$`gc%GD@dw;`i|WihMT;W}4V9XD>X6 zD^URGG^w#nEbiEI*8nL`{alqOy{;t)-`V86CGZ^2?+69uNq<&~LR$c@6S z;_NqnYgM%PiAX_v-Ffpu*GxOy=D2b;%N~$kCYiqy<69-$RSRC&tcWlR9s+dB z6cue%LQAVpcfr?wV=O`)2ZZ|kF6SO7&{|P;@oe=Z>tbIgj469GocYuX+ z%9Gv1)|5c=&BUvNs^IA;l&0gK*p5!742Sk_My%QX{&mIlodEhy=_Lbk6dm_`=B*5t z4)ImSO}|s%h1UVn3fEsd;)mDOYp<@d>C}z8n><(@wLe`{28vsg+DEYwa(f66={%#i zl7eQ!!;4-s)HH10#q!`NssN{Cyj1NioVN8F%MzUAbFXgPS0QMuu~g&7Y*#>l>24@w ze8gKyjWM=v-FIwZhfSUqL1;jArgQ5o69*9jDkyIoP1m91K1QdkPtSjTl}8h{Y%Plk zg6#%=o=S1@m?TqG_BEx=4??h-tES}!G!=$!7WHr_2}r8Y6=>S_RTR+%+{ww0aJFE~ zZv9FgX`*eM2wS)>jj4Bn6c(k;t`yWs9ekK-c9tIBQ z_#4t*-+>+u8}47gdcv-|h@hWVAKdOk3G{4nD=1x>@vuhCs(tNLs)P}%A zN4|GWq@dV8R18cM2l(Dyiwd7966c?$t8EctW{~^(W9Ya-qxA@v`mbqcUjI<8X=PvK z2exMaJ^FR!HQY*NhwO-fKOp+ze+3@8e~wS5EiD?Vv;a5DDiF+N1{5u6nVN5<3X22r z%_~qYG%q;q))}j$993hh*W7iWH>_^KHP z3Sm1BDKA8dtF`&J=$v4QZ^-W8bweehRr)@sSeqps)R2+RGX==Yeno0X#?3#&nuhoK7E(5{7z zzju{+zP&NgUA;LIUe*!2LjzuvCbyIY8U`5f2+}%-q2k;QQQfoy@6>=wnfZs}?0f*^ z1gvo=a-WZr{wee;MN3!+wLuAT3|a0m&?~tjO1LQ>Lc|$8UoL(Css`Q$D-RNIpmZW+ zG^T^W05~6_WFkx-yjywig>tzv%3bWbov|v|kw6q^zw33{Y6@vUr!*H@^FSR<*?GTC{^XFP_O1Jd%`vZy19KZ4NF5&7*> zgo_akTzY5%t?YW)WiO~L>_9Ws`Gd#KywDA|k&&uM4zbK0sdT^6krJ|K7&)|gvM<)U zHvSE&#doM^X-7@m4Br+-=N-&0%!M(8*NN=~1kCbx>`{S1_JY?;np+$#kY!E6-|7y! z_8IH|7Uv+6K$%1k7Q0l4<-NDjGi#uT{0)?#Kp-t2L}#AT+2I2p_?V3(_6cQcm;bfr zB{zqT=2q4J(!cJ_p*W_q8u)=@O#NdRRkaTHV;ny%zrQ@#BhtH$z~nDk%+(cr4+QuP*UVKbl$G?Qv1rc{Q6fdc|+q~ zjYb6lFQ9vHA1kKUkmD3PNdoq!Y63mTJavYA%bZ5x=gO4o;3cwk>;A#T;9t^{<=a6Zj#I!QHdj}(lBbIp^&SeyihP5=gF|8+*C?4VQP)Pp(&IyR~L{+(~fny*3}wYz+I$ zKrE(Gi@$wu3upGrEV)LgT{a7uk$=k#{f`KIvvnS=eYm2M)zCQX?(eUxo58+AIJ=D5 z$)=0EFtL#pBiPixAyu=d4GMxoa;&3A=(|sa5vO{tk;Nl$&f~0DF~0`i`EZE?T%GPk zu51sU$vIs2M?3kfLC25~lU`CMo36uN5wvb#Qv5^2YYUQO(6#aXZ<#`gI~A4auP=Fc z=By^+F3o$GOT0?<=Jv!#%2Rls2uigQm;$8HShRk-yh^*l0!_6p{Wyxlzd%&sRN;u2 zQaMexB9{i0x|K~67k|(GRvZeVp(&-b9;~3`wU}w z9G@%>FQtsee+A$*)WVNHYY`GhK|_xp`7_7Vc~Z0KvLg4;GM&t^u)1DjITqM>r^-s82^9HX`k;fgOEjq)e7-fG_1X4(y<<2^?L#n z7>PoXReG`5}CkbE~U4igZ(aZ)>=6+2XRq!n_BwCXBu`Dn35&vN!y&&|7h2 z9Z>$F@L+{Yl(I81!l+Vk5n(V^csLLf#4w6lc6qaSSa|r6%#+5IlC>Az^BinBDiR8O z8CWzvhg>7-5IUr3AF$&o|JeNt=ZZuEUl_OQ54vzzVb~L)_&sp1MJEY8aPKQ2RvqTb zFmS(Ff}e;UOjn_|jF&7XxAsDwnPp&wXvNDPy?18%(Bg;F$COSEs_YGKX{V10aBI~Hp!GzEW?2}7~u^z!5};yh?z`3eyxWCEiX3NMyJj`DDR z8ffq%5nnzt$qG}N#N=$>(^Tw#AVfze~lhf4Glm;EWS>IAZhf- z+kl+0I(49sdZOl?4^j8U=5SIoK$4_~Y^U(+P;g&4E7R8}Qa{D_qL$15_ns@VMh#n< zI(+bupuy}X4g%#b0SDgcMH=)m)%4+_R-GE`6`SI%{P1VSuIWavV9EetToKgn&0Ex5 zDGV&$qM1h z(ED0L{yV**!)_7<#`%5GN!m}GMEO6TM{DD8Z9SiUj8_60JAlhi?QZ{K*6P&^vxH0n z*~%dsoY^~)Km0JdYTL^|c~#9k>y ziJ9RQHnKbKt4B{2LnbsDi7oT?E9HSlorup)IIgeNk zO#z>8?5gt^@`Q&7{c$KP{Br~#nY=}=!tVl&Wnz+i?FGKegO$wm%)0eg7(yfs2T5f~ zpP;5cZ+$3xzF3UMT}dl7<5MzMcj-^z;2<(49+F0?Gld2{eZ+++{9TRWzk}6{nz{S? z482w(z5&o^*HP-$Y(VY1ABUHk0a$6b%QsB;+k4GAPStJGmVu>{#>V3F17nsCAkkAt^Mp_J$qrXqcp{>|ia*>lB(W&xrx|4)_knau;pP(gND=}fu06xjeIpTrjbPhhI5SaBV0(shNQuv_-&H|j$Clw zc;J-pH~(~s%N&g>di-dJk}EK5-yaFcpDIGl=|j}4NWjlD?b?e2FTNRGY6jqdEy{LD zS=N+Y(vl@QrNVkvQJ_DmfR!HUFIFyFI4P;P_@V5HV`l|d_NEg!SuJ>O_P?oJvF1oz z0EW}ZE+3uf`Hjf^klQuRBmR4=t^K>De_kCHz8Dod zHvsMS(pM^%Et;1)bnw!&QNzoEDtp6_3R8~vJPXu(+DoD5aF>+ekdCPe4kn7 zy&ff7jAS-<|1_rk)8ru=d<{@Mr#mY@dm`p-?~9^jmKtmw4SVjr+)06j=GZ4aH1%6V zX08^(G0}jbCpTrFcknxnNY=hoE>9si%xUyxl)9(P@HKaimB}bfD&hBtUiDB3by_?Z z7`ZB7DIdM!uC(*6tc|lWyuXEs^2r_rawdPAx3==kdDb`y{A;yU`4m1Gy z+jcDo&AxaUrE#Z)_e{;$ze++G4#YZ@oKo{HpK*AzSnh}4CIaF^A>=zFsc6A@Zb)S{ z9DppN_PvjBY|RFcWHekN0qZ4nURCzQ2ep#V8>l{`v<$2u^;)~)7l|E*8gEUXF!onT zMSU}a0<$}cHCMbMY71K8rv{`h-l##s$l`65Gy%i{sX1i)>`l|h>9t~+AJ!LC^Q)wn zlO7_LCQ@^2CwO?q?*&1qL-xPjRpj}Ie^cQBQ!um3)8=8YB;Hh*@(H#!DBjJ#SsU+Z z8XE%^03}ztFVb7{39$Paps7OL8Yo6qe}RAU$H-FfjVDBij^8lNMG_%%VzS8PMvN92 z^c~eBn79&Z06D)e4Ckkm08!C_&6w2=nDs~_OYe+k8mi1b}RMRxvv z7xv^cqV8Fvbl|((`lE!HvV|(1}Q{^o!zNb z&Cf^Y3l;gIVK8Umlg1;3J*N%N)Nd*1Q}z^np2*VU0R?4bZq^h)_+@ zTe4NNxU*7!O$FwJ2U6c@z@(p?8z=W2YY>vOR!tkOGjxPxndYyQC+hl?uq^_P3A`sp z%o6=IkUJh2ev5lfqvk4+RmgC#Qp!q&D447qVPr-3>8e%e;XNhXbyj#{2&(T*!ruTr z&l$skggkY|sH=WhvWpiHT|9qXozc_D*91+tW${X~C~|>Njjb&B_m8Z&zu|`_;PY zhfm0|bh9isyglJ>8{1XCrNe{%ZU-HPV6G-Bmo2(1t#tU(wBdt?1rBC+6l-1&?0XSt z-fu1?SfkZm1H_dm8H7$4Dc4?8&H4E|74hR^u^pJM<(DxmFZ~cJ)%wlep(O!FNW|V!uQZWR%2a@sCor$-&Pi zi}hfLOKWhuUtt1W5v9>r`c1JfT+1tIthUb9HdH?I z5>6ioFR>^fzZV7DO=VB4s`Kwgp|L{rO(oENu;FY`mS2df`qPIuWQ`yD+dcz|`vzS0 zh8Tqw7HfW2eDD;~IZJxI2FP5UHdru3N5{EW2XQWqyF}4lf5Li9>7V$c?%8H_TSNw7 z{g=j6Jr8k(aB?gVlK>D9OaqH$VDvhSjHwBAqoTfYCyG!|#;~665a`ZO;gK)YhYDR= zA^wR51dTZ!)-VI`Z0?+2opPofu?K=LQ>oxFF0dD6v zKxb*#v<=m7z8h}um28u-=y+@UQ{iB4cU7_F!BVm54*d6_bX$AV9T{Uvf0~e&lNxxY zAi=)}0oH#DHZ-GR+}0yHX@D6`BxU3uen<&4XUHvBfUgpgDFITucz>LS&-Q6tv>f*T zfK2WOOkWBlWSwiV`Xf=d&R2;YomA+vS;c!b3`iSv?$Op007c7U;(e$CavtfGb;XiPc~gZEM_#9Jux$sUzLX+h$n~Nul53qgdYriCRc~6M z)?jq(>s@-I2`s0P%il7?hpry2vrQsVg^cccfWdkBV>z4<0NbgK<6rK=!PnjncUc_j z@>g~_;h}I+GdOP#%Y)_R$5Qdwy%YKr_We!Pq_J~sG0}nPia#D620Rq@uvl|1%e3+J zF*3`)6Kt)J9TxTcV5+SLsCKS&?ehao@Umn7@RsYhaRp%jvi8{IpLOq@;UeO4j97?S zA#yARvM2QP05DXj5XbKHFHEXN_dEny$eNfndKeh~IvPYsO--L#KSK{({uE%?jqYpB z@%y8M3fBkkan*Y4k=CB_J5K7ll;w)DKNN-rX;={|LYfJ!g?pfI1~BvnAa#J&t@mh; zMV+f&cpWGARfW}i1xVGM==j=%hRluOq-L-TEEQX>;*rI3Qb!C}nm&5?SX;D;c)Ghb zm152HK=p^fJ{D`XunH&cMSdB>$2R`|36eekxA+``3wH-KfOvABD=fK1Y-YUS5 z7{|+yQR(gH#zwEq_J0U|BqNH0#E~HmcS3`AAlzSn`O75e>{jG?l~90ffo#8IS{2v@(S0?Z_dC6+=@E}K9#%&f!_w~0`J zLwIv0MZ>}O18r5`_ekJKR(pb}-AVfy5i;c;%|rt7&+FbN4J=}@4!s-NnsHjpiJprg zUk3`N31UuXp$CQ3FjXrp>I*G&ZKO5`F&KPxNEq7{Td}BV^|snH*&nxzdK>rlo+XF>$Tfw3=a;tq9<0y5h^^gM*EPYFJ005pwxSe62B{dep8$e zy>Uao-aS#k(PzUh5h`S%?_iTNe9go9_Yi470=}wGSsIc)oA*>;|MJ(tFkzVG9lJgL z<_UjWQ6J`UbnD(Su)5T-|KIoLM@xMcXO07A(XLvB^032Ecw6d;Z2!+2d5?Dqj0Vk_O zIW2!MJM>--yj)}!y5m=4X)cBe*{&t#*8s!8EdE_Q*R!`>!&#C{^x!LRp=sydaC@&h zCCGR8iHUi7@M9|tmHKNLSO5+@v3NvmR_-sd#+F_c-6t_R;J7uhGE9Ny&5&vEktzxw zPA<@=NEjedG3RF5-XicwMos@$vnKS$@n9q7%2(-{&UP{1rg8(~bR@yv%nZV>$RPn7 zd{0m`D0Bw~6zV;9ig&}7Z1D^clDa|*A(K9f9J>=oO8v1Adi?0MA}<=rE13;QzC6yA zzU8=kE!czRSEToKE0)y3*e z!-}A9daYb{kYZr%08S7XY(gQ1K_UDs>4{x&HywIXXkfAap3#IK-MmS_l%IDW8S4+y z!>Sk6L9lvYrY5Npya~B>7@Doyph4(P0`jJa3{g)87Q=JY6Gic+1;00K9^yvEUY78vC!_XFSSV4PVB%t4go-tqSi)(#!ZRkqEu>Kzl zfO8EULZgxem02f!(}w^6AOJ~3K~#s*9}-lCj!Lcs1}x~#E2hlL4phDY?0rGIaI3%T zZ9N~H255}4&S;22gB&agMJxXMQrNv$GH^(earM5&w9VHoU)~vGw z>j5gIKveuR7#<`a6AwKj-u{&j?=2!_-y!r`ZGTdbO&V3y8d&t?kY6t7>`e(Mx!QYq z6QvI1L4aU)y@laHdasyZ;kpl5gR;TlG4+GGgOnG;ZV(<#hWMR@URZju4y-aCv8vu{ zVf6O7mi;dR244g8=^K*K63~9|^|#TqV^7$7Q3?!1AoU`c#}E+IJex z78_sqQR=DFo!`nBGx~wV{M@vFGX))!AW>u8R$$u`UDfKtIXj*Drss;7BpO%VFiHI0 zw>AK^pPKJOP45-GbM#)h7R&XdRvz#S4{8Op)_VEKI6v;YK<uf#qV6O^gE`|uHc1**2VQnQ zk@5j!kfn%H1wi5d1lq|vt-NR$PaR%VgQ0b{ zwqpMaD{!)6f4DOTIh$wOVxkvLd2Hng4W_0`6TQa3+P`e^*u>(3UuTRPbx~AYZ1D5u zE$>uqmp33nGX`l;B^3afqrIohJGQ3QnO(YUc@K>ed&Tge8tj#F$Tf;k4T~=uQkX$F z5SaC+?uK#gXTnp_6s%FAL*@x#EX{aF7sX95ZFSB}yu zu5;r>MhQ*t@gGN*IUE>vlkjRX6zMFiOUVpqW|{hf@d`@!*2@8DK*<`MAJWhu$63FA z3u@l}0HkOLugLYXO}<6$XnNmB#GF_kLoGB+f&4FQI;;wkO8?lxj z$4zVo57F};>^=)}A92qbHLS_eDj9U6fuua|yGTm|tK=H*v=AH#_c)C?hK2PMdW>mc zc?(sOVuNELCd(fo;)-*MO2Kd$!k2jE918ax{D2G;)nz2~abvXQ?_9XhZi z;IcQaiYE4n)m)_U@;t7w^7H* zL(DyWgpXvBW}so42+8{^^boR~3PVe-UNX5u)J-jav5OAE-^Q)yb=N>b4lv?YplBB0 zsBfrqr?TCSqaUxuk&o9x?g+Q{3JsDZf1|VW_$niNuec-;YhcMQ{5*F5(T1C{CXIbK zskksFXfV5D1M^mQ;sCJe5ui~cl0%(;9R4>iiInx+NkD9}y4P7B?)VO%xkBCZMth0? zei~S@eLRm$0r58pkxPuw`^ZqxpexVKhu${UAl&z|vAq-YzNM51;!khJJ?RDC(t-dQ@+}7#U(1I{(paGU6!h|{_6P#IYK-7#y|m*@C6ne2B4W(2XuA$gMqUF|--pLHr3 zDx~phg$j-FYawQiG#kTj5=loP61k%jHSd0e`gNNjcZQv6>Nq6aX76lVX>{)umq*R< z8KPy>rkkqA?j4rUH}`>zveN5fl9K{2d*g06{LnO40_%S(4p}XQuKJ|DKw`eg2w^CK zB$oaZc-3k=9830ifNB0}gq{S}wIe1eR6;KYGaRWa9z-;J6<}_lx2vxDgA9whmjB_L zI7gQMp@)v?`bHOK5E6go%udd|yW=U~a0s}Zg4GZAAU%p6+0|vB<%l4)CH5~^@m4Cw z(YDbHEPB%EHRj$AMCh?|gbGQ;;w=2`@FGdperf*UO~s1GdlO=yLnlXUzIyM?wIhm)ut$R8&L*U`Je8Ynp#x!aMpyf=|Ppf@wCol zYv234NM+Va=<+3NGuhGk--`D{0!|(jw^J<+4}Zr>*K__1AUe+Xn+#QuQM-OqXmCBe z#qltphla)|Q_uPT@t{3P&r&c|-5DCq5VREZpwM`8@E_6GrGeER;9=%llNvrD32)4- zW!=-aNzJh9X`o(bkhT^x;hOToku|1!1}oQtI3fNnXfSG3l8FV&3orD3S}e) z8m3{Xgb01`fH6^lnXJK(`ev5_!*2nyS%=Z(I5>TztFG$mz`SHy>;tO}p#gf>hkP9v zc(M5Yg-Gn}?Kt%MDjeUwEBvIQGMZ$_-->HYf1`By^0pAEAgFF4#=xq2{Jx7)hLrp+ zZRF5WTTo?hJm^#LUR42WAJneyTtY68J_Lx*7Fl1;t3jiM;g4|K9*Mu|dx7taIwf=P z1kkWmJDqsj&h%K(u%ZFPF*+YWJZx!@GK?3j5WkdEC;-63S#b>r;MbzcA-wf*!BMC}wh5yzP+>wr|M|e6tAyv)RhZ1fg3wB}f0F;1Nnqq14k8(6aZb6dr-`s=dB zk6xNmQru6oOhH!#@}pk)Cb0eQDpl*{G2YI}b;EEJ4{^GCT~~r2YNkrJhJo^cV`s4vOzuPv_26DJE#ia!kIs`r8iIM6nP+7n%w*1)Ry>wQJGwDj+%myNh1E{$o?iC(i-5r$)UFcby`aex`4d=ssr2o4k7Cy8Z*z*j~Oat2r z6{`CY1^E=iw+!8uTrS9WLnxhR&Z6SKFQMg7ZP-agB}gYF8FxhIrM^z%_3th zoGH@uu#q2%-mKVEVUP2GA-N$7&gvSz?8@rnL8AcKy=+x}?~kn)MSpb-Rcf@K^lqk4 zUtsDlL^#zU#PpE^>ySzgC$2qpPq4g0n9#s5;js-GVxRO@MgZ*-^Wq@jku1&(~7;$aVu&`=?8Rl!{OXofda0>|~ndZ?KVy>4_<()YNw-9YX{0lg`L7j%Ee)ew(j)K& zPwEOawE=n1)NKOV3|*EgG`}T=^Rmi-=?{1BkCy{_U>SP$C64f5-qfD^RUwtF1CD%V zrSALEV=(_t+?#^K%5;Ceavexf!LX&4*{w9J2V5e;Qtpym4t^j)g~Vl9p~7HR*z>z# z#9i6j+Hh#ayT+hpP&6dJXM_E=vL`;MHJkT}qc??tCCeX1S1fz+rrasxSoS7QS1`Nl zw&zWa97~`4IItfR4?G%I#4~vUXgjy86qMaA0L7uedjvKs{obMh$^-y<`<%Teo_cho z&Qo6&{z@cH6wL<4-rrqgWN#-kH?skK3Bk0yLGyrjCkz)UykjPzd+;@1BmO%t8LTY8 z?}qaw!;#HM9xxhL#6oIq=p^?8hFk{}UeJ@af>^%Y&jFPyw9D8vqW;4*CIxqOHBfR{ z$Z=Pka^uz=3hx#9ufi@ecw=4^o0s;I*|1j*-5K7%s(t2rS@w?jg&AW;{4hQzJ6Y4R zH)?heZ-@Ke2EKek&C@-fA!wEblbH#pM%(PKev2`}gMrOBxVMP)%9#L=_)(3%XaFBs zBS6UE#H$52Ywg~q2ZDS#JRqHg^OuKPgE%np@fz33q zl<<6%@Ep^FOtRaPhlD4Qq^nvB@uDoT}qcMz5$9D%4KNbam@jiT-^4v4SI-?hf54A&h2=07J@ENHI?~*AxcM6b@>AoL+d)rS4 z!&YxBo)L8%$}!QCMdDj#9W$eto~xirLa7`)sXhi?3JknVgehI+;QPStXSB&+R5_%G zevIEfUc`yJ${7>#sTvR1E|Wd?Hrams12fbd^t51xHLxm|EuNIzzwqJA31u^NDSM-K z3-gvp{;R`l)xL4=IbyCD9`uBxaBZ=pRe;;cHPjnflNEx~N$T}QPYSaw!&S4<{~e+K z8{`U`@_&J}LFf8ni6<6$u2OkPpck=VmUkv`?p0m{7@D;tGBrSAUwT8C%|-*yS?Fn} zfmQXUwivL;)THlO^(h2K+zJ#-R|h5W-J)Ml7!26XsP{iw+FQPR{*#}Xp*ERET^rKC zs$8~cUh43nEPFFrm$EnhY(1v8fAK5ecmM|pvw%p=;L0QAseh&13qh;B(0fIl5cfme zNlb#e6*^NN`MgZ(G;!`J9*Q#`?Ov~pfaIP31ZqB2*BU)0B;53tkfGF|tPx%;OCnPP z%o^@H6&QAdpqFtKCQK-y!u9Grqmikl;Ah3(8$f+(Uoy2V7|OtsWm&3v{N8Ib%Sx9f4;oM$(o8{58Y9->lOF;+%>5P84DiFG zCOk+l1M7+@AY=o?zx|!77SEH^l9_|Pirlgoi45$22iWsm7uepUa}4LO zdHF7$FRCuk`y2)_6tG>XIVk@wy2ZAn?BAbl>jpgEm5xlVsvxH1H*50&pW2RrGTF_8n9gkc0rPE8CRdW zMOwZ*{4A#dYgW8y2m`D9|NXEqDLLW08D%5xj>||-@Oi)nIcdLMXHCEl?+vVE4dd!e zb*Bs1lh6}zq5>chWN!@(I&{OjcVw^j#(hP7k?)GY_Otco&m81OmcVoxmNaY#Fz5fr z(6ql?XvDDbCOquM?z^q>4S|;-o=}abHLxtY1~u9=|1-W=#T#}C1OC`1D^#dq zg9Yv?ccSl0rP_A=c+P0Rc0jTN_@A>0ssDT4qs!0uF%`o;8g>J#;;;9PO3KdrW!Cu7 zmqsNdI0}FnM_~*Re)PS-NI&^uA`VO8vWas)C*>gB0i12@y`e#eW|$N}uOAP1PhPC{ z7E$0<@$Q&9JTHtX(s`n&q<2$N-Ay#2nk$KMP=_v}}}v^xJ_?81{xs0De! zjLwJ0%hcejyNp#Y(G6cZ3F6<425gss78~UIo6dIpd)8B{&jv9yL%kX{1M9$FzH@2v zupz%s8&)#Z5MXvs%RKGOKVtB#ulSBL4Oi4sAKsRcB6RSdaQhDF$Zz0U(EwLl_oh zk>>;Ns@E9zD9K*wQS>JCAhL`U3vF8x`5GYpitO&pcw@GztJH53MpoSx?Ts8>NRs-B zP`cvnrIFPo4t_9RN?4bXM65LaW&SZ(!VrI3{VxIrUFrMxrPGd*Wf{lG*uH{{?Z$`# z$TC*RvV6z*zrJ@!k|HO|D=Y@q#)Wg{54`@$zorfwWQQENu;+#ZI~J$txY67Me^B_D}nwC zx*PJGBY&sF`|W)p@Vc#@bd`6WFs^(RepfJ>%_19{fB2oXvwo@pA_R?N{{`}3wx znUXtWip>@mtINbRYxGP5@a12C>W?&Nl5XxUl^fv)ufdFTZGs_HTbu|7+FOnCF$i$V z62Ky^=_3TF-5Yg>lK4<5XeiWX5i;|TB!v@y*nNCQHv+r<4K(afKW>I$7{1K*!6W<@;#dx)TJs8$_OKkFwu8`SJG~ z3^E?gh7mFYYu%!Y^I|&Nua_m<1z<=_pQNbbYcE5e;zAgPlEIx?6>PzOfr?i(Q@Yhq zFVp}-94uh1<`zy5CrKR1l&)4{lYv233E-@=9Q**-{U1@gPPItF2<&@-_XCaNY$_L_ zOrwiZKzyjc@bJ(jmXD#NPzl3ZnPtM8!lVE~1k7q=(U|Wy3m9@Oz{1e3!Vn>iEQSoV zx=7ME&KTaa__Uh!V=@NU`_utpScf`n=)jhaxCO|Yq>dL+&Aj}4Mz-70uxXoOU>PMe z2%rX?w%hDd{YPdliQ{Q0LSkTTzH9DayG^=Nl5sO+ITw;ZD5eY^fTAldLQFCN&3^8d zP(4l;bH(cd$6|@4fj~6Ckeia|FvvRvg`;g6^~@}#A)r>6N!rf<4O@&~kB)Q68Y_q#=|Ltwhei(Ze4z+A6N8yEQS?s_%-JSU;>pbT zOX3G<(D$DYFzeJ=SnrbGOcoedOAX>{pED68Z%S7Y_y7(I#VcGT)}3`ULuOp1Bx-=SSK`UYhej`x zFX2IO>X4{O$$D>UB`FV>_+ub*Py4Ls^ zolKfwXg0RbxtX+`2I@Bn8VtP;TY9f(;5qkC0%ID{X6C-*UK@53kUI__zR+2?H|RN~ z2UV+#Uxuw&5IH(2@C!M44e4Vu1IhSlXSMWqWX>ZaD4kN$ejkjqfrks z_I5;de)Dv;eVy4$;&@tCT@9>Fch9{5vb-3wbQvVLHQl4);!ymxOOP^TpfN**JV+XM z0w4dtye|DP{iv;OA*c>`xYNi|^J`PWZhJ+BsXyVB&aH`ghJ4jf6tw^vo7r z2n@bPcxhaP_&*w1BqH@^FMB+#YyiuTDQii(h5$Am*PZn<34o`kO;6!(pI$!J7$ig> zOhSXIe*G5Iu38OyhcU7S0d&Zae<9lw9-Z*F6%ktkAdoHUbDO+y?X^)Q8O;|7 zGXS`drgU$DIIQApE=6pL8}1{Yy@lWbW^{e_KUTf15U4t$x^PfVWQ+o$ReESy^O84g zX0NIh_CtKptYzKb;J)4Q6i~fdZA;ysW4rVg#HS0cE*?(A5b^d;s*H})`g?x@8~M4n zIBtgLNIBv9wIepCZlfTr)xrR9H&%v(`cCf(ZMi(aufH3<=VE#T&Pp zUmCNXhznxqh=z<>QPRJs0h4~x{SA5!7$Q8jQEf}^pQBz#@~8+29Sw5}_B}7sVh~(T zBhghH*_wKKu^1wvf#)ea%#u&^r1=}d^*!^@J;AKF;Wvw{Q`hWRh6)LIKlHwKbymrP zMNd{jj_6O#Z_8O5Ow8b#>&2(X-y<`685&F-5W016(^Kc!R)z1XX~!NA5|BzWpLH6zgyGm`fOV?uU{MNx7zH|?J__nIwv+b?@P-}!lJ7dAiZ=rq$t&| zg=W8yi-@<~fV z?4L!G%_{T~_May_Sp@RC%8@TbCN?u;wel1)4P=c|Kb~HYYt`Bq>n+#*lUZDzjZvjV{N1Y+nqJww-Mw{eH-tdGsOn! z9$ChHLtwn!imDfNCwI zx?qBXH-b!s^K5tEp=hng9B6wC5t8dkA<}d?TBu_Z-d2C?{{_O^cz7XV7@nRpR(> zZ*LKF39Pplh|n{}8@4FjShGx}_tzcFcR>;f43=JP!r@kzbntsFa48yQr)!B0c>?Vel zoNP@M8Z)Z1Nhyt>K2s55iOGJ@xPaj?O!LT52 z*8YYDl`%;``XFHTpSzEcp_m;{0t^%OX33obkix>-cZ4298dzKdt&P#bIRNYTc@rgU z^+{KzoyK9SP_I2bNkgsy`d!$Q_lZyol8>?~Myn3qLPsHW8q~y7Duz~EnbifX=$ayP9P5R~!&Scgz|j;5N{YKCwLvNlgA(cde7ik{+zu&kVa7AsHBJ*!7`-<)gO- zop4xc3@i@q$XdbNuQxYSD3qQ%UX*Nd2l75~P=pG(F9W(zsGI;Z4T-Dd?~le6S@Q|= z&=S~Az4A@ckWDNPaX?ftXCQ>wRZK!Wv zDta>bK_(zJDCr{XBo2qn=t@};NpMN=Moq5?vlRms9v}lR1xmlwy@k51f}(+5*WN6| zKvD0$JmJkG9o?xt!?#)kix@DabWf}KSBoCv0T+wRRwjW4`NG;#t-GVrF~f|*?yEFa&m z=1ReT7L2iNq;;nEh{d2;6xum6mt*9fr-4-iJ2jWfQOgX zcnyCPV?FDK28g>#0kX#mFsvF;@K@`!W1wcA&V-$EyEd%KWYQl0eIRFS_gS&nE;9&e z#2HSyGB|nbXP7k5@Ti)3G0A{9I8QVQjy4$nCqI(brGIiJ`NsNj3=9vl|47OBglYtmTc&zfco>IPyY8g~O< z{7T!yR}aNmZ3+$Wa8(E&NBPEG@p*C+k$93BM@Ikn(^GK%Lja3CI}33xd!EydJzLAY zq=5ei0!jTuVe6Co_48y9Z^w`@nfbj5LDwvsL*h>@g^c6ed(L$T-L+588F5&8P(^4t zAAj27rH0|_ftPj9aCNjnFDtVO>AfRL$LPY$L;~6eUken@@V%!(G#}!wXk4AFIAAE; z6@WS!^1X4n>90mQV|zdb*4o7jQsP?MFO_Z5cL0oohM9u??!CeV7b0`~Xk*~9n4z`v zDWK{tf2X1U^8`}!hLuzxZdXh_XIY3yz;*4mly3pnk2}mme zW3)=y)2 zFj#z)AHxjjQLcI3L}2PKy1z~@%#MEo2i^^+SzTXZSWq!K2A}Ju?UcYD5%90ICxZmC z#9<|5d7qYE9xNJo^kUJN^d^yNV9_w?I~5pqWA`<8=;BnZ@U*fZxlw;_#P5+WkAQY& z?D`5f>-qya*SLba+Pob#E8jO7?ut1jJ31wK;mKaY*zT8sRRAhM)xN%XLENbh``xl^ zXZ2X7fvCo6>AAQ16c?iS>Prxtmf|}rNY8<=?N)lRo(3x4)c#QLckFb%^Fy12AB7@YP|ZLc&t!}#Mc;WBgr6Ua zUaYz=f%Ok-pLwKKAr4|amWp5)jE9NqiqgO$$Is~+wXH_hbJPpjw0&ifan|-ufxY5E zZ`9kg^Xl-h8gZ+@xHwDQmM)5hZN^$lg_N-$K;XBl7n=HRVl74u3j#Z4pFUh%Ks?nW zCw;$q0&Te%$4M6gs+q+}7g?mS10zT63dW!+UsC$i^xfP0sW>qZbl zEV4>P5o=~2dt1K{kGG@c3=X{f7EbP~G8*oRn)o-O@#C?7diSuTxl204iVm_nk9Vpq zcU(L~j_P<^hI~OdfbHJql|TD@WKS87sQB=fBv4YinN3*vdgyNu{78}HE@Px%CU-Cv zyDE;^Q4L>e58e%OQIJ?kpeKf~B{8?+C*JHmwYp1J$tkx89KH39c}5Pgz|i`k5xfc8q2h%KTdlhKnZ z0^LtEZj0uMg3x{Xx^LykdQsY`VW+;CrM~9CZz(;FeWw8>mkF8=1BtzjxT{Z5w{ElH za95DAMT(N{Y07R}*BgpC``Q*>Lw}p@p1nYlZI8;32$%>n@af!CqT=IGbj3wT9aaJ< zN^=rYyJ^1`*gI#bdP8JqG3;d|;aYIdvUH6*VR8XISS)9vB^HYZCNuen{c^@a zF*Hd!4idheI;fx5l2|!{`WdEl_N20ZQdG1Y72c~zp=j{5=SYz<^y@&;9M9fF66EfC z6{y=B9(@pE!HX+vDw4yC7c>J2aaWC7cA)yL_l$?T0*=bE?T5*+w&w>wwlV@3bAw-a zuLjl&*N%uS$?W@63DOUY7Aj24&qeVymx6T*eX=wMuP4tf5FESb8SzmF1uqtjsjmn# ziAD1=Ii-61eo<#F6l2p<&w;j0%mmBSWRCKjDo+mv0oFX^Op|TN48noH%*T4pi^dg! z!$u2p^03Mp>lqJ6gM);h+^<@%0}oCTy~bw?91TNpq(tD~EcUE;j&!67phtv89=*-{ z(b7}KP*_`&@SJfBdiEda??>zRSW<@ESl+xsCk_DnUIJ=9>+)vmxGv7~CA?V7KGRzm=Af~_5){75f6yz_yjOs>d$W*9nm8QR zq>FY5E7Q2*0Y}dXQ}xXvG!j_z?Yv)hA2AJu?N0*xUN)Xl%{|M61I5VjAPl?LZxx_- zt%YHAdXVVRqJhKTZYVDv?4Ns)f3qeYjmS{;ueCk{X^-K-VK)o!kT+Z;*PjVQ)gK9X z1J_C~p@)$Lx%-|647fxP!x~V?cXja9w{fDp(ulaLb+RNa8dsmXMOwbxSbPy-TuW8i zft&7{Hv^JPBWr{ng`I<$f9|wN$el3-Q3+w>C7~B<@AE+UOZt8=8QvgiBAKZ@VXmB& zsQ}!!39mq}7BYt?id1Wcr+C2gQp^L6##M8_P=es z6=&_X+$rAcKr)MrV0W!b6d6woy?aD7s<>}Sd61OvT^HO7wVwb7-UEmyfun;F`K*wm38nPYm-o4{>y3k|xedru6nkOa3T*dopCkm*khNdIjX;UY2)2$%%gN(P9c(5Yc0A?3la=~3|k&{C8# z4gH1pN-Y-)aSOz=e(Z zEQ~{j{FrH-l-uHLQ8w}%328VyS@ejoI{cl`0UAVIej8XE z_ttx6kL&Ctb%Qh!K$wu_o;6r7ehYE=qP|Ay_h{`G@NA`+8THQ7c zvRSQRbZLMYktAyzySTebh?8Lr!oAD2#ms1>c=AxO@G@)Dc@t)jeT5&?s&lIy^%{^w zc^_xG0!P;Ep|`cG7ubKkFtU7Q6RID0L_FEq+KM9|twG(IjmFCu6dK+Q$-da$+4PYW z8uY&90y41J_g;ApQ$g~a>GTVjxLB6sF zl?<#J;k~i|!dkDYaoS^QIT^88cEnj2THEoDt^(x78SYmjVW^uWV?32gaXiQn4?QI; z@nlKpH9!yPfGc`td(y}vubz@Xp+VwI)+k`aH-PN2(9hAJJ=)tl(6DhUYFB*(yYVsx zskLSq(vsGMlTV!Y=$bPIRij~s6|jM|`Tm({_OsEy2Bh01z;NUtF@2IS;Okc+v9K>B zTfox{e4(@q6*@8qi6!tPj#_R!ln4^m;sY4??5#KT)BrP|#@s7vr8x_YYkIJ%SL@k( z;BC|M#&R{}9r7lMfwfOy2rUV{2AH8*IJ;-R{Kn8rdT^ySWo)>QM}8A1o)`K#8n8#% zZpVo|6*&0XJLqUJCag(@^xsY!elqd#Rn?MY9WuVQQBao0)`jy*JE0Je@=I^HP$A3d z^uO+M#AT%UW{(V%q}t5%wElr3UiK5t1VR)|n5jR(+<1f&lIvOIW|Xk@WoCo`0T6@J%f zU=6ue9dUB7{TclIGl!4jz^iZL%#mY;%NV5UBuMLI*>-<(-r4n5A!l`)DJTPrU2I%5 z=W3}_`n@Dc#WG~W6oht6KXqsc3NM|D*p%eZ8(CV03VApw1)fLrEH%Q=5JADLr>7-f zjk-N#Jr!yVC>ex*6zufQ!VFeYG?4VxsG_jBPx7ACMSwmp3#_AQNr*Kdi9`ff`VYq_ z99XOaZ)j7#h8Qe{yUjqGpyNu2GB_)7qP)s@8G~Zp`(>N_y|_Ayt=*q(5VV1{;m*qv zCEMAbO8^nKVM^WeKINGrkSz(Z1|*Y9?V8|9JSdypCT{;R^vKz|*o@Brvf)Z7xZjCN!P`W^pv+Jg4MrLb z#EzZVFN)w=;#mV+`+l>5argIpru=1K&ocmdfs86#YkFcCf^z02a^QPdwur=*1XI)4 zvLwVBkbwS|c!nZyGzu?P6>w}_@M9~v92k0|D7M@SrSohnj(+w9j(xTsa)*XQuA1sn zeksNt^P|%INmUjlgMW(E#K2;g8}Ghwx+L2kk%6&BV|jO|r09zINFO~i^fe2~E=in{EfaFD0E@KCN0PICxMFB%rR?vvgn0n850^)WZ>o;EU#5~ z*N+C)z^lC%Gj-heucGRr=z^F9_87`@YEdTIGZ1l?)Ken

    e%^s+y>^S$7rK-=nX)pI=7g!sxap0{%Byg;*zBP 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� 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 z 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 literal 0 HcmV?d00001 From d5ff5f5e3c0f4085d767b6812ed087d0c9a15ee7 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 16:06:52 -0500 Subject: [PATCH 011/577] Update a.js --- a.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/a.js b/a.js index 3088eecc..2ef48bc8 100644 --- a/a.js +++ b/a.js @@ -5,7 +5,7 @@ if (typeof VERSION !== "undefined") { } var img3 = document.createElement('img'); //Gooby -img3.src = '/Snakefall/Snakebird Images/Cherry2.png'; +img3.src = '/Snakebird Images/Cherry2.png'; var canvas = document.getElementById("canvas"); @@ -2120,7 +2120,7 @@ function render() { } else{ var img=document.createElement('img'); - img.src='/Snakefall/Snakebird Images/sky2.jpeg'; + img.src='/Snakebird Images/sky2.jpeg'; context.drawImage(img,0,0,canvas.width, canvas.height) //context.fillRect(0, 0, canvas.width, canvas.height); } @@ -2482,7 +2482,7 @@ function render() { context.stroke();*/ var img2=document.createElement('img'); - img2.src='/Snakefall/Snakebird Images/pinwheel.png'; + img2.src='/Snakebird Images/pinwheel.png'; if(isUneatenFruit()==0) context.drawImage(img2,c*tileSize-tileSize/2,r*tileSize-tileSize/2,2*tileSize, 2*tileSize); From 6bf18321aefab6c409833968b9b23a3e8153d0f0 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 16:07:25 -0500 Subject: [PATCH 012/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index 2ef48bc8..ff138a39 100644 --- a/a.js +++ b/a.js @@ -5,7 +5,7 @@ if (typeof VERSION !== "undefined") { } var img3 = document.createElement('img'); //Gooby -img3.src = '/Snakebird Images/Cherry2.png'; +img3.src = './Snakebird Images/Cherry2.png'; var canvas = document.getElementById("canvas"); From 5038025fd8d5333dcf3bb515ef977eb2d00be012 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 16:08:19 -0500 Subject: [PATCH 013/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index ff138a39..2ef48bc8 100644 --- a/a.js +++ b/a.js @@ -5,7 +5,7 @@ if (typeof VERSION !== "undefined") { } var img3 = document.createElement('img'); //Gooby -img3.src = './Snakebird Images/Cherry2.png'; +img3.src = '/Snakebird Images/Cherry2.png'; var canvas = document.getElementById("canvas"); From e5b5bb2548ba081980c35113e1c2d95551110e0c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 16:54:25 -0500 Subject: [PATCH 014/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index 2ef48bc8..269101ca 100644 --- a/a.js +++ b/a.js @@ -5,7 +5,7 @@ if (typeof VERSION !== "undefined") { } var img3 = document.createElement('img'); //Gooby -img3.src = '/Snakebird Images/Cherry2.png'; +img3.src = 'Snakefall-Solutions/Snakebird Images/Cherry2.png'; var canvas = document.getElementById("canvas"); From a192559b231de829dce8713f18e468b5a176dc56 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 16:55:42 -0500 Subject: [PATCH 015/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index 269101ca..5b506fdf 100644 --- a/a.js +++ b/a.js @@ -5,7 +5,7 @@ if (typeof VERSION !== "undefined") { } var img3 = document.createElement('img'); //Gooby -img3.src = 'Snakefall-Solutions/Snakebird Images/Cherry2.png'; +img3.src = 'https://github.com/jmdiamond3/Snakefall-Solutions/Snakebird Images/Cherry2.png'; var canvas = document.getElementById("canvas"); From e717f870a97e51c1f5e2569cb2670b77ab6dca9d Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 16:57:27 -0500 Subject: [PATCH 016/577] Update a.js --- a.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/a.js b/a.js index 5b506fdf..b49fb04a 100644 --- a/a.js +++ b/a.js @@ -5,7 +5,7 @@ if (typeof VERSION !== "undefined") { } var img3 = document.createElement('img'); //Gooby -img3.src = 'https://github.com/jmdiamond3/Snakefall-Solutions/Snakebird Images/Cherry2.png'; +img3.src = 'https://github.com/jmdiamond3/Snakefall-Solutions/blob/master/Snakebird%20Images/Cherry2.png'; var canvas = document.getElementById("canvas"); @@ -2120,7 +2120,7 @@ function render() { } else{ var img=document.createElement('img'); - img.src='/Snakebird Images/sky2.jpeg'; + img.src='https://github.com/jmdiamond3/Snakefall-Solutions/blob/master/Snakebird%20Images/sky2.jpeg'; context.drawImage(img,0,0,canvas.width, canvas.height) //context.fillRect(0, 0, canvas.width, canvas.height); } From 3ac509e46e791258e99b77f31708a4a65682b815 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 16:58:23 -0500 Subject: [PATCH 017/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index b49fb04a..93ee196f 100644 --- a/a.js +++ b/a.js @@ -2482,7 +2482,7 @@ function render() { context.stroke();*/ var img2=document.createElement('img'); - img2.src='/Snakebird Images/pinwheel.png'; + img2.src='https://github.com/jmdiamond3/Snakefall-Solutions/blob/master/Snakebird Images/pinwheel.png'; if(isUneatenFruit()==0) context.drawImage(img2,c*tileSize-tileSize/2,r*tileSize-tileSize/2,2*tileSize, 2*tileSize); From 45e02aa16b39abb80e854a0447acf231f85a920e Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 16:58:53 -0500 Subject: [PATCH 018/577] Update a.js --- a.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/a.js b/a.js index 93ee196f..66a53d9c 100644 --- a/a.js +++ b/a.js @@ -55,11 +55,7 @@ var exampleLevel = magicNumber_v0 + "&" + "0000000000000000000000000000000" + "0000000000000000000000000000000" + "0000000000000000000000000000000" + - "0000000000000000000040000000000" + - "0000000000000110000000000000000" + - "0000000000000111100000000000000" + - "0000000000000011000000000000000" + - "0000000000000010000010000000000" + + "000000000000000000" + "0000000000000010100011000000000" + "0000001111111000110000000110000" + "0000011111111111111111111110000" + From e73a13aed1726c7fb9a0fcf0956158f036385aed Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 17:01:15 -0500 Subject: [PATCH 019/577] Update a.js --- a.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/a.js b/a.js index 66a53d9c..93ee196f 100644 --- a/a.js +++ b/a.js @@ -55,7 +55,11 @@ var exampleLevel = magicNumber_v0 + "&" + "0000000000000000000000000000000" + "0000000000000000000000000000000" + "0000000000000000000000000000000" + - "000000000000000000" + + "0000000000000000000040000000000" + + "0000000000000110000000000000000" + + "0000000000000111100000000000000" + + "0000000000000011000000000000000" + + "0000000000000010000010000000000" + "0000000000000010100011000000000" + "0000001111111000110000000110000" + "0000011111111111111111111110000" + From 22f6b7fdf883a0458268d019e45d16540c4709df Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 17:02:54 -0500 Subject: [PATCH 020/577] Update a.js --- a.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/a.js b/a.js index 93ee196f..72271f5d 100644 --- a/a.js +++ b/a.js @@ -2465,7 +2465,7 @@ function render() { } function drawExit(r, c) { //Gooby - /*var cx = c+.5; + var cx = c+.5; var rx = r+.5; var grd = context.createRadialGradient(cx*tileSize, rx*tileSize, 1, cx*tileSize, rx*tileSize, 13); @@ -2479,15 +2479,15 @@ function render() { context.arc(cx*tileSize,rx*tileSize,tileSize/2,0,2*Math.PI); context.fill(); - context.stroke();*/ + context.stroke(); - var img2=document.createElement('img'); - img2.src='https://github.com/jmdiamond3/Snakefall-Solutions/blob/master/Snakebird Images/pinwheel.png'; + //var img2=document.createElement('img'); + //img2.src='https://github.com/jmdiamond3/Snakefall-Solutions/blob/master/Snakebird Images/pinwheel.png'; - if(isUneatenFruit()==0) + /*if(isUneatenFruit()==0) context.drawImage(img2,c*tileSize-tileSize/2,r*tileSize-tileSize/2,2*tileSize, 2*tileSize); else - context.drawImage(img2,c*tileSize,r*tileSize,tileSize, tileSize); + context.drawImage(img2,c*tileSize,r*tileSize,tileSize, tileSize);*/ } function drawWall(r, c, adjacentTiles) { //GOOBY From 56b25c03d8a5e2b6f3a8ef1598370ca7a8bd894b Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 17:05:07 -0500 Subject: [PATCH 021/577] Update a.js --- a.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/a.js b/a.js index 72271f5d..5344f79b 100644 --- a/a.js +++ b/a.js @@ -5,7 +5,7 @@ if (typeof VERSION !== "undefined") { } var img3 = document.createElement('img'); //Gooby -img3.src = 'https://github.com/jmdiamond3/Snakefall-Solutions/blob/master/Snakebird%20Images/Cherry2.png'; +//img3.src = 'https://github.com/jmdiamond3/Snakefall-Solutions/blob/master/Snakebird%20Images/Cherry2.png'; var canvas = document.getElementById("canvas"); @@ -2120,8 +2120,8 @@ function render() { } else{ var img=document.createElement('img'); - img.src='https://github.com/jmdiamond3/Snakefall-Solutions/blob/master/Snakebird%20Images/sky2.jpeg'; - context.drawImage(img,0,0,canvas.width, canvas.height) + //img.src='https://github.com/jmdiamond3/Snakefall-Solutions/blob/master/Snakebird%20Images/sky2.jpeg'; + //context.drawImage(img,0,0,canvas.width, canvas.height) //context.fillRect(0, 0, canvas.width, canvas.height); } if (persistentState.showGrid && !persistentState.showEditor) { @@ -2458,7 +2458,7 @@ function render() { var rowcol = getRowcol(level, object.locations[0]); //drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); - context.drawImage(img3,rowcol.c*tileSize+(tileSize*.1), rowcol.r*tileSize+(tileSize*.1), tileSize*.8, tileSize*.8); + //context.drawImage(img3,rowcol.c*tileSize+(tileSize*.1), rowcol.r*tileSize+(tileSize*.1), tileSize*.8, tileSize*.8); break; default: throw unreachable(); } From 9535524f1096de9769128e5e494101d3b670a828 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 17:08:13 -0500 Subject: [PATCH 022/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index 5344f79b..8a335f8b 100644 --- a/a.js +++ b/a.js @@ -2456,7 +2456,7 @@ function render() { break; case FRUIT: var rowcol = getRowcol(level, object.locations[0]); - //drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); + drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); //context.drawImage(img3,rowcol.c*tileSize+(tileSize*.1), rowcol.r*tileSize+(tileSize*.1), tileSize*.8, tileSize*.8); break; From fcd7dbdf9680be326b070bb4f16978c41438904e Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 17:15:59 -0500 Subject: [PATCH 023/577] Update a.js --- a.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/a.js b/a.js index 8a335f8b..92a2102b 100644 --- a/a.js +++ b/a.js @@ -1596,10 +1596,11 @@ function isAnyCheatcodeEnabled() { !isGravityEnabled || !isCollisionEnabled ); } -var background = [ +var background = "gradient"; +/*[ "sky", "gradient", -]; +];*/ function showEditorChanged() { From 585193539b6425e321c3c9bf9506c2f41e096e12 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 17:21:41 -0500 Subject: [PATCH 024/577] Update a.js --- a.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/a.js b/a.js index 92a2102b..267cfa78 100644 --- a/a.js +++ b/a.js @@ -2338,11 +2338,11 @@ function render() { break; case EXIT: drawExit(r, c); - /*var radiusFactor = isUneatenFruit() ? 0.7 : 1.2; + var radiusFactor = isUneatenFruit() ? 0.7 : 1.2; drawQuarterPie(r, c, radiusFactor, "#fd0c0b", 0); drawQuarterPie(r, c, radiusFactor, "#18d11f", 1); drawQuarterPie(r, c, radiusFactor, "#004cff", 2); - drawQuarterPie(r, c, radiusFactor, "#fdc122", 3);*/ + drawQuarterPie(r, c, radiusFactor, "#fdc122", 3); break; case PORTAL: drawCircle(r, c, 0.8, "#888"); @@ -2465,7 +2465,7 @@ function render() { } } - function drawExit(r, c) { //Gooby + /*function drawExit(r, c) { //Gooby var cx = c+.5; var rx = r+.5; @@ -2482,14 +2482,14 @@ function render() { context.fill(); context.stroke(); - //var img2=document.createElement('img'); - //img2.src='https://github.com/jmdiamond3/Snakefall-Solutions/blob/master/Snakebird Images/pinwheel.png'; + var img2=document.createElement('img'); + img2.src='https://github.com/jmdiamond3/Snakefall-Solutions/blob/master/Snakebird Images/pinwheel.png'; - /*if(isUneatenFruit()==0) + if(isUneatenFruit()==0) context.drawImage(img2,c*tileSize-tileSize/2,r*tileSize-tileSize/2,2*tileSize, 2*tileSize); else - context.drawImage(img2,c*tileSize,r*tileSize,tileSize, tileSize);*/ - } + context.drawImage(img2,c*tileSize,r*tileSize,tileSize, tileSize); + }*/ function drawWall(r, c, adjacentTiles) { //GOOBY //drawRect(r, c, "#976537"); // dirt From dd2f2a93181ec972980188b067729354fb47a42e Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 17:23:26 -0500 Subject: [PATCH 025/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index 267cfa78..1a238e8b 100644 --- a/a.js +++ b/a.js @@ -2337,7 +2337,7 @@ function render() { drawSpikes(r, c, getAdjacentTiles(), level); break; case EXIT: - drawExit(r, c); + //drawExit(r, c); var radiusFactor = isUneatenFruit() ? 0.7 : 1.2; drawQuarterPie(r, c, radiusFactor, "#fd0c0b", 0); drawQuarterPie(r, c, radiusFactor, "#18d11f", 1); From a955a9832a331018c738074a808fdb2e9c2c99ca Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 17:53:29 -0500 Subject: [PATCH 026/577] Create CNAME --- CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 CNAME diff --git a/CNAME b/CNAME new file mode 100644 index 00000000..6e6d36f6 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +newsnakefallgraphics.com \ No newline at end of file From 4ea76013dfa8768a5d06f913e49c00fc6001c2c5 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 17:53:42 -0500 Subject: [PATCH 027/577] Delete CNAME --- CNAME | 1 - 1 file changed, 1 deletion(-) delete mode 100644 CNAME diff --git a/CNAME b/CNAME deleted file mode 100644 index 6e6d36f6..00000000 --- a/CNAME +++ /dev/null @@ -1 +0,0 @@ -newsnakefallgraphics.com \ No newline at end of file From 208a8b930b8b2ad4af318ade78e30c172d69d401 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 23:35:39 -0500 Subject: [PATCH 028/577] Update a.js --- a.js | 110 ++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 82 insertions(+), 28 deletions(-) diff --git a/a.js b/a.js index 1a238e8b..fc5af251 100644 --- a/a.js +++ b/a.js @@ -5,7 +5,7 @@ if (typeof VERSION !== "undefined") { } var img3 = document.createElement('img'); //Gooby -//img3.src = 'https://github.com/jmdiamond3/Snakefall-Solutions/blob/master/Snakebird%20Images/Cherry2.png'; +//img3.src = '/Snakefall/Snakebird Images/Cherry2.png'; var canvas = document.getElementById("canvas"); @@ -672,8 +672,8 @@ document.getElementById("backgroundButton").addEventListener("click", function() toggleBackground(); }); function toggleBackground() { - if(background == "sky") background = "gradient"; - else background = "sky"; + //var bgLength = backgroundList.length; + //background = backgroundList } function toggleGravity() { isGravityEnabled = !isGravityEnabled; @@ -1596,6 +1596,8 @@ function isAnyCheatcodeEnabled() { !isGravityEnabled || !isCollisionEnabled ); } +var bg2 = "rgba(230, 230, 255 * rgba(220, 220, 255"; +var bg1 = "rgba(0, 0, 255 * rgba(20, 20, 255"; var background = "gradient"; /*[ "sky", @@ -2112,17 +2114,20 @@ function render() { if(background=="gradient"){ for(var i = 0; i Date: Wed, 22 Jan 2020 23:40:25 -0500 Subject: [PATCH 029/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index fc5af251..b3d921d6 100644 --- a/a.js +++ b/a.js @@ -1597,7 +1597,7 @@ function isAnyCheatcodeEnabled() { ); } var bg2 = "rgba(230, 230, 255 * rgba(220, 220, 255"; -var bg1 = "rgba(0, 0, 255 * rgba(20, 20, 255"; +var bg1 = "rgba(45, 47, 71 * rgba(19, 22, 74"; var background = "gradient"; /*[ "sky", From e2ce236126f7d78f77dba1a40c503a231697cd2c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 23:42:08 -0500 Subject: [PATCH 030/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index b3d921d6..cfa827fb 100644 --- a/a.js +++ b/a.js @@ -1597,7 +1597,7 @@ function isAnyCheatcodeEnabled() { ); } var bg2 = "rgba(230, 230, 255 * rgba(220, 220, 255"; -var bg1 = "rgba(45, 47, 71 * rgba(19, 22, 74"; +var bg1 = "rgba(150, 200, 253 * rgba(133, 192, 255"; var background = "gradient"; /*[ "sky", From db3194021cc460d5617415f51faa1a1b5b7a2710 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 23:43:55 -0500 Subject: [PATCH 031/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index cfa827fb..cdf781be 100644 --- a/a.js +++ b/a.js @@ -2462,7 +2462,7 @@ function render() { break; case FRUIT: var rowcol = getRowcol(level, object.locations[0]); - drawCircle(rowcol.r, rowcol.c, .9, "#f0f"); + drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); //context.drawImage(img3,rowcol.c*tileSize+(tileSize*.1), rowcol.r*tileSize+(tileSize*.1), tileSize*.8, tileSize*.8); break; From 73f8a24c1e4b9c086ef20936416eb14b2ce75608 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 23:45:14 -0500 Subject: [PATCH 032/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index cdf781be..b7104576 100644 --- a/a.js +++ b/a.js @@ -2603,7 +2603,7 @@ function render() { function drawSpikes(r, c, adjacentTiles) { var x = c * tileSize; var y = r * tileSize; - context.fillStyle = "#E4E4E4"; + context.fillStyle = "#B2B2B2"; context.beginPath(); context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); From 6705f31f666d8d62482eff7b4c1a0eb0c9cc9f52 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 22 Jan 2020 23:49:32 -0500 Subject: [PATCH 033/577] Update a.js --- a.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/a.js b/a.js index b7104576..39ed0862 100644 --- a/a.js +++ b/a.js @@ -1597,7 +1597,7 @@ function isAnyCheatcodeEnabled() { ); } var bg2 = "rgba(230, 230, 255 * rgba(220, 220, 255"; -var bg1 = "rgba(150, 200, 253 * rgba(133, 192, 255"; +var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; var background = "gradient"; /*[ "sky", @@ -2116,7 +2116,7 @@ function render() { for(var j = 0; j Date: Thu, 23 Jan 2020 01:02:35 -0500 Subject: [PATCH 034/577] Update a.js --- a.js | 53 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/a.js b/a.js index 39ed0862..e9107500 100644 --- a/a.js +++ b/a.js @@ -2658,29 +2658,37 @@ function render() { return tileCode == null || tileCode === WALL; } } - function drawSpikeSupports(r, c, isOccupied, canConnect){ - var boltBool = false; + var occupiedCount = 0; if(canConnect(0, 1)){ context.fillStyle = "#444"; context.fillRect(c*tileSize+(tileSize*.3), r*tileSize+(tileSize*.8), tileSize*.4, tileSize*.4); boltBool = true; } if(canConnect(0, -1) && !canConnect(0, 1)){ - context.fillStyle = "#444"; - context.fillRect(c*tileSize+(tileSize*.3), r*tileSize, tileSize*.4, tileSize*.4); - boltBool = true; + if(!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(1, -1)){} + else{ + context.fillStyle = "#444"; + context.fillRect(c*tileSize+(tileSize*.3), r*tileSize, tileSize*.4, tileSize*.4); + boltBool = true; + } } if(canConnect(-1, 0) && !canConnect(0, 1)){ - context.fillStyle = "#444"; - context.fillRect(c*tileSize, r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); - boltBool = true; + if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(-1, 1)){} + else{ + context.fillStyle = "#444"; + context.fillRect(c*tileSize, r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); + boltBool = true; + } } if(canConnect(1, 0) && !canConnect(0, 1)){ - context.fillStyle = "#444"; - context.fillRect(c*tileSize+(tileSize*.8), r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); - boltBool = true; + if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(1, -1) && canConnect(1, 1)){} + else{ + context.fillStyle = "#444"; + context.fillRect(c*tileSize+(tileSize*.8), r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); + boltBool = true; + } } context.fillStyle = "#555"; @@ -2703,19 +2711,23 @@ function render() { else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (CORNERS) roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4}, true, false); roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {bl:4}, true, false); + if(!canConnect(1, -1)) boltBool = true; } else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {br:4}, true, false); roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {br:4}, true, false); + if(!canConnect(-1, -1)) boltBool = true; } else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tl:4}, true, false); roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4}, true, false); - } + if(!canConnect(1, 1)) boltBool = true; + } else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tr:4}, true, false); - } + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tr:4}, true, false); + if(!canConnect(-1, 1)) boltBool = true; + } else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (OPPOSITES) roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); } @@ -2725,22 +2737,27 @@ function render() { else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING THREE roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); - } + boltBool = true; + } else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, 0, true, false); - } + boltBool = true; + } else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); + boltBool = true; } else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, 0, true, false); - } - else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ + boltBool = true; + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ //TOUCHING FOUR roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + //boltBool = true; } else{ roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.6, 0, true, false); From c5051e37664b9d3be6d293248288501ccd91f43f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 01:13:21 -0500 Subject: [PATCH 035/577] Create patashu-remix-1 --- patashu-remix-1 | 69 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 patashu-remix-1 diff --git a/patashu-remix-1 b/patashu-remix-1 new file mode 100644 index 00000000..bc025bb8 --- /dev/null +++ b/patashu-remix-1 @@ -0,0 +1,69 @@ + + + Snakefall + + + + + + +
    + +

    + + + + + + +
    This game is a clone of Snakebird by Noumenon Games.
    + + + + + From a9d52d55b8f7aacc963ea9e2a7a301d006ff127d Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 01:14:30 -0500 Subject: [PATCH 036/577] Delete patashu-remix-1 --- patashu-remix-1 | 69 ------------------------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 patashu-remix-1 diff --git a/patashu-remix-1 b/patashu-remix-1 deleted file mode 100644 index bc025bb8..00000000 --- a/patashu-remix-1 +++ /dev/null @@ -1,69 +0,0 @@ - - - Snakefall - - - - - - -
    - -
    -
    - Controls (hover for hotkeys): -
    - Arrows/WASD to move - - - -
    - - Moves: 0+0 - - -
    - - - - -
    This project on Github: thejoshwolfe/snakefall version ???
    - -
    This game is a clone of Snakebird by Noumenon Games.
    - - - - - From d4613f6fa7c2073dcb4d8ac019d48f8fa3b78006 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 01:34:15 -0500 Subject: [PATCH 037/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index e9107500..b28e7593 100644 --- a/a.js +++ b/a.js @@ -2813,7 +2813,7 @@ function render() { var r = rowcol.r + animationDisplacementRowcol.r; var c = rowcol.c + animationDisplacementRowcol.c; context.fillStyle = blockForeground[block.id % blockForeground.length]; - drawTileOutlines2(r, c, isAlsoThisBlock, 0.3); + drawTileOutlines2(r, c, isAlsoThisBlock, 0.2); function isAlsoThisBlock(dc, dr) { for (var i = 0; i < rowcols.length; i++) { var otherRowcol = rowcols[i]; From ca75abfaa80abd349e9a2f51677e2ae18cc65883 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 01:47:47 -0500 Subject: [PATCH 038/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index b28e7593..e9107500 100644 --- a/a.js +++ b/a.js @@ -2813,7 +2813,7 @@ function render() { var r = rowcol.r + animationDisplacementRowcol.r; var c = rowcol.c + animationDisplacementRowcol.c; context.fillStyle = blockForeground[block.id % blockForeground.length]; - drawTileOutlines2(r, c, isAlsoThisBlock, 0.2); + drawTileOutlines2(r, c, isAlsoThisBlock, 0.3); function isAlsoThisBlock(dc, dr) { for (var i = 0; i < rowcols.length; i++) { var otherRowcol = rowcols[i]; From 93cc7b20aba9bf8c525c8ec339c225e369b91672 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 01:49:39 -0500 Subject: [PATCH 039/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index e9107500..02385d7d 100644 --- a/a.js +++ b/a.js @@ -1708,7 +1708,7 @@ function move(dr, dc) { } // do portals separate from falling logic if (portalActivationLocations.length === 1) { - var portalAnimations = [500]; + var portalAnimations = [200]; if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { animationQueue.push(portalAnimations); } From 47d8f2f9f63e3d97d01c9fceddcbc5a63b012aca Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 02:42:39 -0500 Subject: [PATCH 040/577] Update a.js --- a.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/a.js b/a.js index 02385d7d..0e3ecf78 100644 --- a/a.js +++ b/a.js @@ -2522,6 +2522,29 @@ function render() { else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10}, true, false); else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); else roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); + + if(isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1)) { + context.fillRect((c+1)*tileSize, (r+1)*tileSize, tileSize/6, tileSize/6); + //context.globalCompositeOperation = "destination-out"; + context.beginPath(); + context.arc((c+1)*tileSize+tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); + context.closePath(); + tileColor = context.getImageData(c*tileSize-tileSize/2, (r+1)*tileSize+tileSize/2, 1, 1); + context.fillStyle = "rgba(" + tileColor.data[0] + ", " + tileColor.data[1] + ", " + tileColor.data[2] + ", " + tileColor.data[3] + ")"; + context.fill(); + context.globalCompositeOperation = "source-over"; + } + else if(isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1)) { + context.fillRect(c*tileSize-tileSize/6, (r+1)*tileSize, tileSize/6, tileSize/6); + //context.globalCompositeOperation = "destination-out"; + context.beginPath(); + context.arc(c*tileSize-tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); + context.closePath(); + tileColor = context.getImageData(c*tileSize-tileSize/2, (r+1)*tileSize+tileSize/2, 1, 1); + context.fillStyle = "rgba(" + tileColor.data[0] + ", " + tileColor.data[1] + ", " + tileColor.data[2] + ", " + tileColor.data[3] + ")"; + context.fill(); + context.globalCompositeOperation = "source-over"; + } } function drawTileOutlines(r, c, isOccupied, outlineThickness, grass) { From 305907c952f3a46958b422c6e8246cad3090cdd5 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 12:18:08 -0500 Subject: [PATCH 041/577] Update a.js --- a.js | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/a.js b/a.js index 0e3ecf78..5428fef8 100644 --- a/a.js +++ b/a.js @@ -2501,6 +2501,9 @@ function render() { drawTileNew(r, c, isWall, 0.2, "#976537"); context.fillStyle = "#95ff45"; // grass drawTileOutlines(r, c, isWall, 0.2, true); + context.save(); + drawBushes(r, c, isWall); + context.restore(); context.fillStyle = "#895C33"; // dirt edge drawTileOutlines(r, c, isWall, 0.2, false); @@ -2608,6 +2611,54 @@ function render() { if (!grass && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); if (!grass && !isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize);*/ } + + function drawBushes(r, c, isOccupied){ + if(!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)){ + context.beginPath(); + context.moveTo((c+1)*tileSize, r*tileSize); + context.lineTo((c+1)*tileSize, r*tileSize-tileSize*.4); + context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); + context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); + context.lineTo((c+1)*tileSize, r*tileSize); + context.closePath(); + context.fill(); + + context.shadowColor = "red"; + context.shadowOffsetX = 2; + context.shadowOffsetY = -2; + context.shadowBlur = 3; + + context.beginPath(); + context.moveTo((c+1)*tileSize, r*tileSize-tileSize*.4); + context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); + context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); + /*context.strokeStyle = "white"; + context.stroke();*/ + } + + if(!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)){ + context.beginPath(); + context.moveTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize, r*tileSize-tileSize*.4); + context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); + context.lineTo(c*tileSize, r*tileSize); + context.closePath(); + context.fill(); + + context.shadowColor = "red"; + context.shadowOffsetX = 2; + context.shadowOffsetY = -2; + context.shadowBlur = 3; + + context.beginPath(); + context.moveTo(c*tileSize, r*tileSize-tileSize*.4); + context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); + /*context.strokeStyle = "#7dff1a"; + context.stroke();*/ + } + } function drawTileOutlines2(r, c, isOccupied, outlineThickness) { var complement = 1 - outlineThickness; From d766f1ceeb63c3baebb5209bc12e37b9a018e320 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 13:40:25 -0500 Subject: [PATCH 042/577] Update a.js --- a.js | 95 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 33 deletions(-) diff --git a/a.js b/a.js index 5428fef8..c784ac3e 100644 --- a/a.js +++ b/a.js @@ -2045,8 +2045,10 @@ var snakeAltColors = [ "#6666ff", "#ffff66", ]; -var blockForeground = ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"]; -var blockBackground = ["#853641","#963c84","#753d88","#5d3a96","#3a3990"]; +var blockForeground = ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"]; +var blockBackground = ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"]; + +var fruitColors = ["#ff3399","#ff526b","#ff703d","#ff851f","#ff9900"]; var activeSnakeId = null; @@ -2117,6 +2119,7 @@ function render() { var bgColor1= bg1.substr(0, bg1.indexOf('*')); var bgColor2= bg1.substr(bg1.indexOf('*')+2, bg1.length); var shade = (j+1)*.03+.5; + //var shade = 1; if((i+j) % 2 == 0) context.fillStyle = "" + bgColor1 + ", " + shade + ")"; else context.fillStyle = "" + bgColor2 + ", " + shade + ")"; context.fillRect(i*tileSize, j*tileSize, tileSize, tileSize); @@ -2126,8 +2129,8 @@ function render() { } else{ var img=document.createElement('img'); - img.src='/Snakefall/Snakebird Images/sky2.jpeg'; - context.drawImage(img,0,0,canvas.width, canvas.height) + //img.src='/Snakefall/Snakebird Images/sky2.jpeg'; + //context.drawImage(img,0,0,canvas.width, canvas.height) //context.fillRect(0, 0, canvas.width, canvas.height); } if (persistentState.showGrid && !persistentState.showEditor) { @@ -2461,8 +2464,31 @@ function render() { drawBlock(object); break; case FRUIT: - var rowcol = getRowcol(level, object.locations[0]); - drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); + rowcol = getRowcol(level, object.locations[0]); + var c = rowcol.c; + var r = rowcol.r; + var startC = c*tileSize+tileSize/2; + var startR = r*tileSize+tileSize*.24; + var resize = tileSize * 1.7; + context.fillStyle = fruitColors[object.id % fruitColors.length]; + //context.fillStyle = "#ff6b45"; + context.beginPath(); + context.moveTo(startC, startR); + context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC-resize*.25, startR-resize*.05, startC-resize*.3, startR+resize*.05); + context.bezierCurveTo(startC-resize*.35, startR+resize*.15, startC-resize*.3, startR+resize*.5, startC, startR+resize*.4); + context.bezierCurveTo(startC+resize*.3, startR+resize*.5, startC+resize*.35, startR+resize*.15, startC+resize*.3, startR+resize*.05); + context.bezierCurveTo(startC+resize*.25, startR-resize*.05, startC+resize*.1, startR-resize*.05, startC, startR); + context.closePath(); + context.fill(); + + context.beginPath(); + context.moveTo(startC,startR); + context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); + context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); + context.fillStyle = "green"; + context.fill(); + + //drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); //context.drawImage(img3,rowcol.c*tileSize+(tileSize*.1), rowcol.r*tileSize+(tileSize*.1), tileSize*.8, tileSize*.8); break; @@ -2505,7 +2531,7 @@ function render() { drawBushes(r, c, isWall); context.restore(); context.fillStyle = "#895C33"; // dirt edge - drawTileOutlines(r, c, isWall, 0.2, false); + //drawTileOutlines(r, c, isWall, 0.2, false); function isWall(dc, dr) { var tileCode = adjacentTiles[1 + dr][1 + dc]; @@ -2514,7 +2540,8 @@ function render() { } function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle){ - context.fillStyle = fillStyle; + context.fillStyle = fillStyle; + var tileColor; if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); @@ -2525,25 +2552,26 @@ function render() { else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10}, true, false); else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); else roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); - + if(isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1)) { context.fillRect((c+1)*tileSize, (r+1)*tileSize, tileSize/6, tileSize/6); //context.globalCompositeOperation = "destination-out"; context.beginPath(); context.arc((c+1)*tileSize+tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); context.closePath(); - tileColor = context.getImageData(c*tileSize-tileSize/2, (r+1)*tileSize+tileSize/2, 1, 1); + tileColor = context.getImageData((c+1)*tileSize+tileSize/2, (r+1)*tileSize+tileSize/2, 1, 1); context.fillStyle = "rgba(" + tileColor.data[0] + ", " + tileColor.data[1] + ", " + tileColor.data[2] + ", " + tileColor.data[3] + ")"; context.fill(); context.globalCompositeOperation = "source-over"; } - else if(isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1)) { + if(isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1)) { context.fillRect(c*tileSize-tileSize/6, (r+1)*tileSize, tileSize/6, tileSize/6); //context.globalCompositeOperation = "destination-out"; context.beginPath(); context.arc(c*tileSize-tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); context.closePath(); tileColor = context.getImageData(c*tileSize-tileSize/2, (r+1)*tileSize+tileSize/2, 1, 1); + //alert(tileColor.data[0] + " " + tileColor.data[1] + " " + tileColor.data[2] + " " + tileColor.data[3] + ""); context.fillStyle = "rgba(" + tileColor.data[0] + ", " + tileColor.data[1] + ", " + tileColor.data[2] + ", " + tileColor.data[3] + ")"; context.fill(); context.globalCompositeOperation = "source-over"; @@ -2560,9 +2588,9 @@ function render() { if(!isOccupied(-1, 0) && isOccupied(1, 0)){ context.beginPath(); context.moveTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.25); - context.bezierCurveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.4, c*tileSize+tileSize*.2, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.1); - context.bezierCurveTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.1); - context.bezierCurveTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.4, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.4, c*tileSize+tileSize*.2, r*tileSize+tileSize*.5, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.5, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.5, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); context.lineTo(c*tileSize+tileSize, r*tileSize); context.lineTo(c*tileSize+tileSize*.2, r*tileSize); context.arc(c*tileSize+tileSize*.2, r*tileSize+tileSize*.2, tileSize*.2, 1.5*Math.PI, .9*Math.PI, true); @@ -2571,9 +2599,9 @@ function render() { else if(isOccupied(-1, 0) && !isOccupied(1, 0)){ context.beginPath(); context.moveTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.25); - context.bezierCurveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*.8, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.1); - context.bezierCurveTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.4, c*tileSize+tileSize*.4, r*tileSize+tileSize*.1); - context.bezierCurveTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.3, c*tileSize+tileSize*.1, r*tileSize+tileSize*.4, c*tileSize, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*.8, r*tileSize+tileSize*.5, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.5, c*tileSize+tileSize*.4, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.3, c*tileSize+tileSize*.1, r*tileSize+tileSize*.5, c*tileSize, r*tileSize+tileSize*.2); context.lineTo(c*tileSize, r*tileSize); context.lineTo(c*tileSize+tileSize*.8, r*tileSize); context.arc(c*tileSize+tileSize*.8, r*tileSize+tileSize*.2, tileSize*.2, 1.5*Math.PI, 2.1*Math.PI); @@ -2584,9 +2612,9 @@ function render() { context.moveTo(c*tileSize+tileSize*.85, r*tileSize); context.lineTo(c*tileSize+tileSize*.2, r*tileSize); context.arc(c*tileSize+tileSize*.2, r*tileSize+tileSize*.2, tileSize*.2, 1.5*Math.PI, .9*Math.PI, true); - context.bezierCurveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.3, c*tileSize+tileSize*.2, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.1); - context.bezierCurveTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.1); - context.bezierCurveTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.4, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.3, c*tileSize+tileSize*.2, r*tileSize+tileSize*.5, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.5, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.5, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.1); //context.arc(c*tileSize+tileSize*.8, r*tileSize+tileSize*.2, tileSize*.2, 1.5*Math.PI, 2.1*Math.PI); context.closePath(); @@ -2611,9 +2639,14 @@ function render() { if (!grass && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); if (!grass && !isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize);*/ } - - function drawBushes(r, c, isOccupied){ + + function drawBushes(r, c, isOccupied){ if(!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)){ + context.shadowColor = "#2c6600"; + context.shadowOffsetX = -.5; + context.shadowOffsetY = -.5; + context.shadowBlur = 1; + context.beginPath(); context.moveTo((c+1)*tileSize, r*tileSize); context.lineTo((c+1)*tileSize, r*tileSize-tileSize*.4); @@ -2623,20 +2656,18 @@ function render() { context.closePath(); context.fill(); - context.shadowColor = "red"; - context.shadowOffsetX = 2; - context.shadowOffsetY = -2; - context.shadowBlur = 3; - context.beginPath(); context.moveTo((c+1)*tileSize, r*tileSize-tileSize*.4); context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); - /*context.strokeStyle = "white"; - context.stroke();*/ } if(!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)){ + context.shadowColor = "#2c6600"; + context.shadowOffsetX = .5; + context.shadowOffsetY = -.5; + context.shadowBlur = 1; + context.beginPath(); context.moveTo(c*tileSize, r*tileSize); context.lineTo(c*tileSize, r*tileSize-tileSize*.4); @@ -2646,10 +2677,7 @@ function render() { context.closePath(); context.fill(); - context.shadowColor = "red"; - context.shadowOffsetX = 2; - context.shadowOffsetY = -2; - context.shadowBlur = 3; + context.restore(); context.beginPath(); context.moveTo(c*tileSize, r*tileSize-tileSize*.4); @@ -2732,6 +2760,7 @@ function render() { return tileCode == null || tileCode === WALL; } } + function drawSpikeSupports(r, c, isOccupied, canConnect){ var boltBool = false; var occupiedCount = 0; From 0b101004d884e0c26a8a48bb96264fec5f2c4b38 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 14:30:00 -0500 Subject: [PATCH 043/577] Update a.js --- a.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/a.js b/a.js index c784ac3e..54516e8b 100644 --- a/a.js +++ b/a.js @@ -2559,8 +2559,8 @@ function render() { context.beginPath(); context.arc((c+1)*tileSize+tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); context.closePath(); - tileColor = context.getImageData((c+1)*tileSize+tileSize/2, (r+1)*tileSize+tileSize/2, 1, 1); - context.fillStyle = "rgba(" + tileColor.data[0] + ", " + tileColor.data[1] + ", " + tileColor.data[2] + ", " + tileColor.data[3] + ")"; + //tileColor = context.getImageData((c+1)*tileSize+tileSize/2, (r+1)*tileSize+tileSize/2, 1, 1); + //context.fillStyle = "rgba(" + tileColor.data[0] + ", " + tileColor.data[1] + ", " + tileColor.data[2] + ", " + tileColor.data[3] + ")"; context.fill(); context.globalCompositeOperation = "source-over"; } @@ -2570,9 +2570,8 @@ function render() { context.beginPath(); context.arc(c*tileSize-tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); context.closePath(); - tileColor = context.getImageData(c*tileSize-tileSize/2, (r+1)*tileSize+tileSize/2, 1, 1); - //alert(tileColor.data[0] + " " + tileColor.data[1] + " " + tileColor.data[2] + " " + tileColor.data[3] + ""); - context.fillStyle = "rgba(" + tileColor.data[0] + ", " + tileColor.data[1] + ", " + tileColor.data[2] + ", " + tileColor.data[3] + ")"; + //tileColor = context.getImageData(c*tileSize-tileSize/2, (r+1)*tileSize+tileSize/2, 1, 1); + //context.fillStyle = "rgba(" + tileColor.data[0] + ", " + tileColor.data[1] + ", " + tileColor.data[2] + ", " + tileColor.data[3] + ")"; context.fill(); context.globalCompositeOperation = "source-over"; } From fa9a6c1b8b8eecfe0ba24ab43aa0e013c046f598 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 14:33:48 -0500 Subject: [PATCH 044/577] Update a.js --- a.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/a.js b/a.js index 54516e8b..26bd859f 100644 --- a/a.js +++ b/a.js @@ -2045,8 +2045,11 @@ var snakeAltColors = [ "#6666ff", "#ffff66", ]; -var blockForeground = ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"]; -var blockBackground = ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"]; +var blockForeground = ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"]; +var blockBackground = ["#853641","#963c84","#753d88","#5d3a96","#3a3990"]; + +/*var blockForeground = ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"]; +var blockBackground = ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"];*/ var fruitColors = ["#ff3399","#ff526b","#ff703d","#ff851f","#ff9900"]; From e6a3a712400df1a946dc0b58fe4adbaee179feda Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 15:21:38 -0500 Subject: [PATCH 045/577] Update a.js --- a.js | 84 ++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 31 deletions(-) diff --git a/a.js b/a.js index 26bd859f..c2356ef0 100644 --- a/a.js +++ b/a.js @@ -3,6 +3,14 @@ if (typeof VERSION !== "undefined") { document.getElementById("versionSpan").innerHTML = '' + VERSION.tag + ''; } +/*$(document).ready(function() { + var fruits1 = getObjectsOfType(FRUIT); + $(fruits1[0]).jqFloat({ + width: 10, + height: 10, + speed: 100 + }); +});*/ var img3 = document.createElement('img'); //Gooby //img3.src = '/Snakefall/Snakebird Images/Cherry2.png'; @@ -668,12 +676,13 @@ document.getElementById("cheatGravityButton").addEventListener("click", function document.getElementById("cheatCollisionButton").addEventListener("click", function() { toggleCollision(); }); -document.getElementById("backgroundButton").addEventListener("click", function() { - toggleBackground(); +document.getElementById("themeButton").addEventListener("click", function() { + toggleTheme(); }); -function toggleBackground() { - //var bgLength = backgroundList.length; - //background = backgroundList +function toggleTheme() { + if(themeCounter Date: Thu, 23 Jan 2020 15:22:10 -0500 Subject: [PATCH 046/577] Update index.html --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 7ea92665..981de610 100644 --- a/index.html +++ b/index.html @@ -15,7 +15,7 @@ - + @@ -42,7 +42,7 @@ - +
    From bee83821594a9fe963dfec77d6185afb6fd1938c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 15:22:40 -0500 Subject: [PATCH 047/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 981de610..ad4953fa 100644 --- a/index.html +++ b/index.html @@ -42,7 +42,7 @@ - + From 6d5cd7f9ed071ffd9f99a55d7970f9f83ff83116 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 15:35:20 -0500 Subject: [PATCH 048/577] Update a.js --- a.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/a.js b/a.js index c2356ef0..ecb340d0 100644 --- a/a.js +++ b/a.js @@ -1616,7 +1616,7 @@ var themes = [ //name, background, material, surface, curlyOutline //["sky",], ["grass", bg1, "#976537", "#95ff45", true], ["snow", bg1, "#30455B", "white", true], - ["bw", bg1, "#444", "#777", false] + ["classic", bg1, "#844204", "#282", false] ]; @@ -2599,7 +2599,7 @@ function render() { } } - function drawTileOutlines(r, c, isOccupied, outlineThickness, grass) { + function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { var complement = 1 - outlineThickness; var outlinePixels = outlineThickness * tileSize; var complementPixels = (1 - 2 * outlineThickness) * tileSize; From 0b350113a009dbdfcdc499ba62588117d6dd9f58 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 15:39:58 -0500 Subject: [PATCH 049/577] Update a.js --- a.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/a.js b/a.js index ecb340d0..ad8dbc65 100644 --- a/a.js +++ b/a.js @@ -514,6 +514,8 @@ document.addEventListener("keydown", function(event) { return; case "V".charCodeAt(0): if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } + case "T".charCodeAt(0): + toggleTheme(); break; return; case 32: // spacebar case 9: // tab From 8cac9e3977419701c8586ce60d0e6e07ef6761ac Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 17:17:56 -0500 Subject: [PATCH 050/577] Update a.js --- a.js | 85 +++++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 61 insertions(+), 24 deletions(-) diff --git a/a.js b/a.js index ad8dbc65..039180af 100644 --- a/a.js +++ b/a.js @@ -1610,6 +1610,7 @@ function isAnyCheatcodeEnabled() { var bg2 = "rgba(230, 230, 255 * rgba(220, 220, 255"; var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; //var theme = "gradient"; +var background; var surface; var material; var curlyOutline = false; @@ -1618,7 +1619,8 @@ var themes = [ //name, background, material, surface, curlyOutline //["sky",], ["grass", bg1, "#976537", "#95ff45", true], ["snow", bg1, "#30455B", "white", true], - ["classic", bg1, "#844204", "#282", false] + ["classic", bg1, "#844204", "#282", false], + ["midnightRainbow", "#070753", "black", "rainbow", false] ]; @@ -2135,20 +2137,27 @@ function render() { var context = canvas.getContext("2d"); //Gooby if(true){ + background = themes[themeCounter][1]; material = themes[themeCounter][2]; surface = themes[themeCounter][3]; curlyOutline = themes[themeCounter][4]; - for(var i = 0; i Date: Thu, 23 Jan 2020 17:36:23 -0500 Subject: [PATCH 051/577] Update a.js --- a.js | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/a.js b/a.js index 039180af..29f09fad 100644 --- a/a.js +++ b/a.js @@ -2068,6 +2068,9 @@ var snakeAltColors = [ var blockForeground = ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"]; var blockBackground = ["#853641","#963c84","#753d88","#5d3a96","#3a3990"]; +var rainbowForeground = ["white","#888","#666","#444","#222"]; +var rainbowBackground = ["white","#888","#666","#444","#222"]; + /*var blockForeground = ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"]; var blockBackground = ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"];*/ @@ -2270,8 +2273,14 @@ function render() { rowcol2.r -= minR; rowcol2.c -= minC; var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; - drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockBackground[object.id % blockBackground.length]); - drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockBackground[object.id % blockBackground.length]); + if(surface == "rainbow"){ + drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, rainbowBackground[object.id % rainbowBackground.length]); + drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, rainbowBackground[object.id % rainbowBackground.length]); + } + else{ + drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockBackground[object.id % blockBackground.length]); + drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockBackground[object.id % blockBackground.length]); + } } } var r = minR + animationDisplacementRowcol.r; @@ -2495,7 +2504,7 @@ function render() { case BLOCK: drawBlock(object); break; - case FRUIT: + case FRUIT: //Gooby rowcol = getRowcol(level, object.locations[0]); var c = rowcol.c; var r = rowcol.r; @@ -2503,6 +2512,11 @@ function render() { var startR = r*tileSize+tileSize*.24; var resize = tileSize * 1.7; context.fillStyle = fruitColors[object.id % fruitColors.length]; + if(surface == "rainbow") { + context.fillStyle = "black"; + context.lineWidth = tileSize/8; + context.strokeStyle = "white"; + } //context.fillStyle = "#ff6b45"; context.beginPath(); context.moveTo(startC, startR); @@ -2512,12 +2526,14 @@ function render() { context.bezierCurveTo(startC+resize*.25, startR-resize*.05, startC+resize*.1, startR-resize*.05, startC, startR); context.closePath(); context.fill(); + if(surface == "rainbow") context.stroke(); context.beginPath(); context.moveTo(startC,startR); context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); context.fillStyle = "green"; + if(surface == "rainbow") context.fillStyle = "white"; context.fill(); //drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); @@ -2556,7 +2572,7 @@ function render() { function drawWall(r, c, adjacentTiles) { //GOOBY //drawRect(r, c, "#976537"); - drawTileNew(r, c, isWall, 0.2, material, surface); + drawTileNew(r, c, isWall, 0.2, material, curlyOutline); drawTileOutlines(r, c, isWall, 0.2, curlyOutline); context.save(); if(curlyOutline) drawBushes(r, c, isWall); @@ -2570,9 +2586,7 @@ function render() { } } - function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle, surface){ - var isRainbow = false; - if(surface == "rainbow") isRainbow = true; + function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle, curlyOutline){ context.fillStyle = fillStyle; var tileColor = "blue"; if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); @@ -2586,7 +2600,7 @@ function render() { else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); else roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); - if(isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && !isRainbow) { + if(isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { context.fillRect((c+1)*tileSize, (r+1)*tileSize, tileSize/6, tileSize/6); //context.globalCompositeOperation = "destination-out"; context.beginPath(); @@ -2597,7 +2611,7 @@ function render() { context.fill(); context.globalCompositeOperation = "source-over"; } - if(isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1) && !isRainbow) { + if(isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1) && curlyOutline) { context.fillRect(c*tileSize-tileSize/6, (r+1)*tileSize, tileSize/6, tileSize/6); //context.globalCompositeOperation = "destination-out"; context.beginPath(); @@ -2979,6 +2993,7 @@ function render() { var r = rowcol.r + animationDisplacementRowcol.r; var c = rowcol.c + animationDisplacementRowcol.c; context.fillStyle = blockForeground[block.id % blockForeground.length]; + if(surface == "rainbow") context.fillStyle = rainbowForeground[block.id % rainbowForeground.length]; drawTileOutlines2(r, c, isAlsoThisBlock, 0.3); function isAlsoThisBlock(dc, dr) { for (var i = 0; i < rowcols.length; i++) { From 8d371205b943e4b13e52a21c8f4c01e531db1f45 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 19:31:03 -0500 Subject: [PATCH 052/577] Update a.js --- a.js | 82 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 43 insertions(+), 39 deletions(-) diff --git a/a.js b/a.js index 29f09fad..e4f934c4 100644 --- a/a.js +++ b/a.js @@ -685,6 +685,7 @@ function toggleTheme() { if(themeCounter"; } function toggleGravity() { isGravityEnabled = !isGravityEnabled; @@ -1610,6 +1611,7 @@ function isAnyCheatcodeEnabled() { var bg2 = "rgba(230, 230, 255 * rgba(220, 220, 255"; var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; //var theme = "gradient"; +var themeName = "Spring"; var background; var surface; var material; @@ -1617,10 +1619,10 @@ var curlyOutline = false; var themeCounter = 0; var themes = [ //name, background, material, surface, curlyOutline //["sky",], - ["grass", bg1, "#976537", "#95ff45", true], - ["snow", bg1, "#30455B", "white", true], - ["classic", bg1, "#844204", "#282", false], - ["midnightRainbow", "#070753", "black", "rainbow", false] + ["Spring", bg1, "#976537", "#95ff45", true], + ["Winter", bg1, "#30455B", "white", true], + ["Classic", bg1, "#844204", "#282", false], + ["Midnight Rainbow", "#070753", "black", "rainbow", false] ]; @@ -2068,8 +2070,8 @@ var snakeAltColors = [ var blockForeground = ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"]; var blockBackground = ["#853641","#963c84","#753d88","#5d3a96","#3a3990"]; -var rainbowForeground = ["white","#888","#666","#444","#222"]; -var rainbowBackground = ["white","#888","#666","#444","#222"]; +var rainbowForeground = ["white"]; +var rainbowBackground = ["white"]; /*var blockForeground = ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"]; var blockBackground = ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"];*/ @@ -2140,6 +2142,7 @@ function render() { var context = canvas.getContext("2d"); //Gooby if(true){ + themeName = themes[themeCounter][0]; background = themes[themeCounter][1]; material = themes[themeCounter][2]; surface = themes[themeCounter][3]; @@ -2509,34 +2512,36 @@ function render() { var c = rowcol.c; var r = rowcol.r; var startC = c*tileSize+tileSize/2; - var startR = r*tileSize+tileSize*.24; + var startR = r*tileSize+tileSize*.2; var resize = tileSize * 1.7; context.fillStyle = fruitColors[object.id % fruitColors.length]; - if(surface == "rainbow") { - context.fillStyle = "black"; - context.lineWidth = tileSize/8; - context.strokeStyle = "white"; - } - //context.fillStyle = "#ff6b45"; - context.beginPath(); - context.moveTo(startC, startR); - context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC-resize*.25, startR-resize*.05, startC-resize*.3, startR+resize*.05); - context.bezierCurveTo(startC-resize*.35, startR+resize*.15, startC-resize*.3, startR+resize*.5, startC, startR+resize*.4); - context.bezierCurveTo(startC+resize*.3, startR+resize*.5, startC+resize*.35, startR+resize*.15, startC+resize*.3, startR+resize*.05); - context.bezierCurveTo(startC+resize*.25, startR-resize*.05, startC+resize*.1, startR-resize*.05, startC, startR); - context.closePath(); - context.fill(); - if(surface == "rainbow") context.stroke(); + if(themeName != "Classic"){ + if(surface == "rainbow") { + context.fillStyle = "black"; + context.lineWidth = tileSize/8; + context.strokeStyle = "white"; + resize = tileSize * 1.4; + } + //context.fillStyle = "#ff6b45"; + context.beginPath(); + context.moveTo(startC, startR); + context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC-resize*.25, startR-resize*.1, startC-resize*.3, startR+resize*.05); + context.bezierCurveTo(startC-resize*.35, startR+resize*.15, startC-resize*.3, startR+resize*.6, startC, startR+resize*.5); + context.bezierCurveTo(startC+resize*.3, startR+resize*.6, startC+resize*.35, startR+resize*.15, startC+resize*.3, startR+resize*.05); + context.bezierCurveTo(startC+resize*.25, startR-resize*.05, startC+resize*.1, startR-resize*.1, startC, startR); + context.closePath(); + context.fill(); + if(surface == "rainbow") context.stroke(); - context.beginPath(); - context.moveTo(startC,startR); - context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); - context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); - context.fillStyle = "green"; - if(surface == "rainbow") context.fillStyle = "white"; - context.fill(); - - //drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); + context.beginPath(); + context.moveTo(startC,startR); + context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); + context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); + context.fillStyle = "green"; + if(surface == "rainbow") context.fillStyle = "white"; + context.fill(); + } + else drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); //context.drawImage(img3,rowcol.c*tileSize+(tileSize*.1), rowcol.r*tileSize+(tileSize*.1), tileSize*.8, tileSize*.8); break; @@ -2631,7 +2636,6 @@ function render() { } else{ context.fillStyle = "white"; - var yes = true; var mod = (r+c) % 17; switch(mod){ case 0: context.fillStyle = "#ff004c"; break; @@ -2708,13 +2712,13 @@ function render() { else if(!curlyOutline && !isOccupied(0, -1)){ context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); } - if (yes && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (yes && !isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (yes && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (yes && !isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (yes && !isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (yes && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (yes && !isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!curlyOutline && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); + if (!curlyOutline && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!curlyOutline && !isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); } function drawBushes(r, c, isOccupied){ From 244e682f4ba2e9ef339a0996a6eb388e2ce2eb41 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 19:55:06 -0500 Subject: [PATCH 053/577] Update a.js --- a.js | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/a.js b/a.js index e4f934c4..f930d5b4 100644 --- a/a.js +++ b/a.js @@ -2666,9 +2666,9 @@ function render() { if(!isOccupied(-1, 0) && isOccupied(1, 0)){ context.beginPath(); context.moveTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.25); - context.bezierCurveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.4, c*tileSize+tileSize*.2, r*tileSize+tileSize*.5, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.5, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.5, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.3, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.4, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); context.lineTo(c*tileSize+tileSize, r*tileSize); context.lineTo(c*tileSize+tileSize*.2, r*tileSize); context.arc(c*tileSize+tileSize*.2, r*tileSize+tileSize*.2, tileSize*.2, 1.5*Math.PI, .9*Math.PI, true); @@ -2677,9 +2677,9 @@ function render() { else if(isOccupied(-1, 0) && !isOccupied(1, 0)){ context.beginPath(); context.moveTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.25); - context.bezierCurveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*.8, r*tileSize+tileSize*.5, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.5, c*tileSize+tileSize*.4, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.3, c*tileSize+tileSize*.1, r*tileSize+tileSize*.5, c*tileSize, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.95, r*tileSize+tileSize*.3, c*tileSize+tileSize*.7, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.65, r*tileSize+tileSize*.3, c*tileSize+tileSize*.4, r*tileSize+tileSize*.4, c*tileSize+tileSize*.4, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.3, c*tileSize+tileSize*.1, r*tileSize+tileSize*.4, c*tileSize, r*tileSize+tileSize*.2); context.lineTo(c*tileSize, r*tileSize); context.lineTo(c*tileSize+tileSize*.8, r*tileSize); context.arc(c*tileSize+tileSize*.8, r*tileSize+tileSize*.2, tileSize*.2, 1.5*Math.PI, 2.1*Math.PI); @@ -2690,9 +2690,9 @@ function render() { context.moveTo(c*tileSize+tileSize*.85, r*tileSize); context.lineTo(c*tileSize+tileSize*.2, r*tileSize); context.arc(c*tileSize+tileSize*.2, r*tileSize+tileSize*.2, tileSize*.2, 1.5*Math.PI, .9*Math.PI, true); - context.bezierCurveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.3, c*tileSize+tileSize*.2, r*tileSize+tileSize*.5, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.5, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.5, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.3, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.4, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.1); //context.arc(c*tileSize+tileSize*.8, r*tileSize+tileSize*.2, tileSize*.2, 1.5*Math.PI, 2.1*Math.PI); context.closePath(); @@ -2701,9 +2701,9 @@ function render() { context.beginPath(); context.moveTo(c*tileSize, r*tileSize); context.lineTo(c*tileSize, r*tileSize+tileSize*.15); - context.bezierCurveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.3, c*tileSize+tileSize*.2, r*tileSize+tileSize*.3, c*tileSize+tileSize*.33, r*tileSize+tileSize*.1); - context.bezierCurveTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.3, c*tileSize+tileSize*.67, r*tileSize+tileSize*.1); - context.bezierCurveTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.3, c*tileSize+tileSize*.6, r*tileSize+tileSize*.3, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); context.lineTo(c*tileSize+tileSize, r*tileSize); context.closePath(); } @@ -2786,7 +2786,12 @@ function render() { function drawSpikes(r, c, adjacentTiles) { var x = c * tileSize; var y = r * tileSize; - context.fillStyle = "#B2B2B2"; + if(themeName != "Midnight Rainbow") { + context.fillStyle = "#999"; + } + else { + context.fillStyle = "#ffffff"; + } context.beginPath(); context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); From 96734a25b05927d514f1838b3aa4b801318fc620 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 20:26:10 -0500 Subject: [PATCH 054/577] Update README.md --- README.md | 125 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 86 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 67276736..24a48245 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,95 @@ -# Snakefall +# Josh Wolfe's Snakefall -A [Snakebird](http://snakebird.noumenongames.com/) clone with a level editor. +This is a redesign of Josh Wolfe's [Snakefall](https://github.com/thejoshwolfe/snakefall), which is a level editor for the award-winning game [Snakebird](http://snakebird.noumenongames.com). -If you haven't played Snakebird yet, go buy it and play it. It's great! -This project is not trying to compete with the original game, -but instead tries to realise even more potential inherent in the genius -of the original game engine design. +# Standard Snakebird Puzzles -This project enables players to create their own levels and share them with others. +[Standard Template](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&29?*z0*z0*z0*z0*z0*z0*z0*Y0/) -## Demo +S/V (Solution/Verified) - A checkmark confirms the level is solvable, barring any subsequent changes to the level. Most checkmarks are links to solution replays. The absence of a checkmark does not necessarily indicate a solution does not exist. -[http://wolfesoftware.com/snakefall/](http://wolfesoftware.com/snakefall/) +|Snakebird Level|Creator|Note|S/V| +|---|:---:|:---:|:---:| +|[Disabilities Act](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&17&29?*z0*10*11*I0111000111*K03*z0*z0*R03*701*704*003*701*E0122*002211122*00221*401110*910111*z0*M0/s0?323&322&351/s1?43/s2?101&102&131&160&159&158&129&100/)|[thejoshwolfe](https://github.com/thejoshwolfe)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&29?*z0*10*11*I0111000111*z0*z0*z00001*704*C01*E0122*002211122*00221*401110*910111*z0*M0/s0?323&322&351/s1?43/s2?101&102&131&160&159&158&129&100/f0?130/f1?292/f2?321/#replay=nmGTi8PB&ullurrdllu*1rdrrr1*1lr0urrr1rrr0uurr1rr0ulll1lll0urrrd2d1rr0dr1r0rrd1rr0rr1rr0r1rr0u*0r1*1r0ru)| +|[Crashing Down](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&17&31?*z0*z0*z0*Q03*704*z0*H01*P0111*G03*20*11*203*E0*31*D0111000*51000111*60*H1*X0/b0?199&170&168&167&197&171&203&165&173&205&195&164&163&194&174&175&206&106&201&44&108&46/s1?426/s0?408/)|[thejoshwolfe](https://github.com/thejoshwolfe)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*z0*z0*z0*c04*z0*H01*P0111*N0*11*L0*31*D0111000*51000111*60*H1*X0/b0?199&170&168&167&197&171&203&165&173&205&195&164&163&194&174&175&206&106&201&44&108&46/s1?426/s0?408/f0?225/f1?377/f2?395/#replay=nmGTi8PB&1u*0lulululululu*3lululu*0ruldl0rrr1urr0rr1ur0r1ur0r1ur0r1ur0r1uu0r1*1rulululuuluu*3lu*1rurrrurrru*1ld*2rururu*2l0r1urrr0rrr1r0r1*0u)| +|[Etch-a-sketch](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&14&21?*M0*71*601*531*60130*331*601*531*601*531*601*034*031*601*531*601*531*601*33031*601*531*601*521*50*91*40*91*00/s0?70/s1?202/)|[inukoblainc](https://github.com/inukoblainc)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&14&21?*M0*71*601*501*601*501*601*501*601*501*601*004*001*601*501*601*501*601*501*601*501*601*521*50*91*40*91*00/s0?70/s1?202/f0?48/f1?49/f2?50/f3?51/f4?52/f5?53/f6?54/f7?55/f8?56/f9?69/f10?71/f11?72/f12?73/f13?74/f14?75/f15?76/f16?77/f17?90/f18?91/f19?92/f20?93/f21?94/f22?95/f23?96/f24?97/f25?98/f26?111/f27?112/f28?113/f29?114/f30?115/f31?116/f32?117/f33?118/f34?119/f35?132/f36?133/f37?134/f38?135/f39?137/f40?138/f41?139/f42?140/f43?153/f44?154/f45?155/f46?156/f47?157/f48?158/f49?159/f50?160/f51?161/f52?174/f53?175/f54?176/f55?177/f56?178/f57?179/f58?180/f59?181/f60?182/f61?195/f62?196/f63?197/f64?198/f65?199/f66?200/f67?201/f68?203/f69?216/f70?217/f71?218/f72?219/f73?220/f74?221/f75?222/f76?223/f77?224/#replay=nmGTi8PB&lu*4rd*2ldlldrrdlldrrdllddrurd*2r*2u1*0l*1ur0l*0dlllurruuulddl1d)| +|[Fruit Fall](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&16&14?*R03*H022*702112*002*10*01*001*10130102*70121*101*101110002*3011*00103*1011*70311*60201100100200021411*10100011211*101000*01/s0?171&170&184&198&199/s1?92&106&105/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&16&14?*n022*702112*002*10*01*001*10100102*70121*101*101110002*3011*001*3011*8011*60201100100200021411*10100011211*101000*01/s0?171&170&184&198&199/s1?92&106&105/f0?31/f1?95/f2?147/f3?166/#replay=nmGTi8PB&1l0uluurdrrr1ldd*0l0ul1ur0uruulllurrr1r0rruurruullu*1ruru*2luurrddllddlll*0u1ulul0lddlddrruuu1lur0ru1u*1r0lluuurdrrr1ullddruu*0luu0ul1r0ul*0u1uuu0uul*0urd1r0ruullddrrululdd1uu0dr1l0uuu1urr0r1rur0uuru*0ruluul1uluur0l1rrrdrrrd0*0u*2rd1d0d)| +|[Block Valley](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&15&9?*G03*503*e02*401*101001*401*40101*201*10400*21/b0?121&112&103&104&114&87&105&96/s0?115&116&125&124/s1?98&97&106&107/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&15&9?*z0*602*401*101001*401*40101*201*10400*21/b0?121&112&103&104&114&87&105&96/s0?115&116&125&124/s1?98&97&106&107/f0?20/f1?30/#replay=nmGTi8PB&uruuu1uuldddluulu0ldllluuu1rrulul0r1uu0uluuur1uluu0u1ru0u1luu0u1ullulu*1rddl0r1l0uuu1uuu0l1rrulll*0u0lddr1r0r1rruu0ul1uuull0uuurull1ddluuul0lldl1llluuurrd0uurddl1ldl)| +|[Block Valley 2](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&17&26?*601*L01*303*D01*403*C01*303*D01*403*C01*I04001*L01*L01*L01*L01*502*B01*501*D01*301*L01*701*90101*J01*L0*21/b0?411&385&359&333&307&308&309&335&361&387/s1?337&336&362&363/s0?388&389&415&414/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&26?*601*L01*L01*L01*L01*L01*I04001*L01*L01*L01*L01*502*B01*501*D01*301*L01*701*90101*J01*L0*21/b0?411&385&359&333&307&308&309&335&361&387/s1?337&336&362&363/s0?388&389&415&414/f0?44/f1?71/f2?96/f3?123/#replay=nmGTi8PB&uruuldluuu1ulu0r1uuluuu0uuldl1rrd*0luurulu0uurul1rr0urruuu1u0l1luuu0ulll*0u1rddlluuu0lur*1ulu*1r*1dl1ruuu0*1u*3l1*6l0*0ldd*1luu1ld*0luul0*0uru)| +|[Spike Maze](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&17&25?*70111*I0141*I0101000*01*B01010001001*B01011001031*00*8100*0100111*K010011000202*2021102020*010002*B010001102010001*5010012011010001*101*5010110020002001000201210200011*901*30201102021002*5022010011*902*402110001221*002111*00*412*0122*3122*21/b3?351&363/s1?386&385&384&383/s0?391&392&393&394/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&25?*70111*I0141*I0101000*01*B01010001001*B01011001001*00*8100*0100111*K010011000202*2021102020*010002*B010001102010001*5010012011010001*101*5010110020002001000201210200011*901*30201102021002*5022010011*902*402110001221*002111*00*412*0122*3122*21/b3?351&363/s1?386&385&384&383/s0?391&392&393&394/f0?119/#replay=nmGTi8PB&1ulllu*1ldll0ulu*0lddl1u0uurrru1*5rdrurruu0ulurrrulll1u0lurrdrrr1lldlllulluu0ururrddl1luuu0luldl1rru*4rurrr0dddrdrrrulllululldlldllulluulluuurru*8ruu*4l1uurrddllluu*6ldrdr0dddluuul1druruu*1ldddrrddrr0u*0l1drrulllu*3ldrru0*0lddr1*4r0u*3rurrrulll1urruu*0l0ddru1dr0ruurru1ru0ulluulldddr1ul0uuruuu1uurulldluu0ldllulluuluuurrurrurull1llurrddluul0ull1u*1r0llu*5ru1rrrururr*0uluurddd*3l0u*7l1uulllulll0u*0r1llu*5ruurruul0*3ru1*1lul*0u0ulluu*0lul*0u)| +|[Fruit Maze](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&17&25?*z0*G0*41*D01303030111*A011011313031*A010*23101*A013131313131*50*210*3301*5014*003131313131*50*2101*2301*A013031311011*A01110303031*D0*41*z0*C0/s0?234&233&232&231/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&25?*z0*G0*41*D01*20111*A011011010001*A01*30101*A010101010101*50*21*501*5014*10101010101*50*2101*301*A010001011011*A0111*201*D0*41*z0*C0/s0?234&233&232&231/f0?111/f1?113/f2?115/f3?139/f4?141/f5?143/f6?161/f7?162/f8?163/f9?164/f10?165/f11?166/f12?185/f13?187/f14?189/f15?191/f16?193/f17?211/f18?212/f19?213/f20?214/f21?215/f22?216/f23?217/f24?235/f25?237/f26?239/f27?241/f28?243/f29?262/f30?263/f31?264/f32?265/f33?266/f34?267/f35?285/f36?287/f37?289/f38?313/f39?315/f40?317/#replay=nmGTi8PB&rddrrd*1ruur*1ullu*1lddl*1drrdrruurruurruuulldlluulllddrddlldddrrd*1ruur*1ulldlluulllddrddlldddrrd*1ruur*1ull*1dll*2ulllddl*1drrd*1ruur*1ull*1d*0luurr*0ulllddl*1drrd*1ruur*1ull*1d*0l*0urruulllddl*1drrd*1ruur*1ulldddllddll*0urruulllddlddd*1l)| +|[Box Bridge](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&14&24?*z0*z0*00*012*F0*11*F011*2040011*z021*5011211*202*70*31*D0*3102*50/b1?227&251&252&228/b2?169&145&146&170/b3?87&88&112&111/s0?249&248&247/s1?225&224&223/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&14&24?*z0*z0*00*012*F0*11*F011*2040011*z021*5011211*202*70*31*D0*3102*50/b1?227&251&252&228/b2?169&145&146&170/b3?87&88&112&111/s0?249&248&247/s1?225&224&223/#replay=nmGTi8PB&r1rurr0uurrru1uruuruurrrdlll0luu1ll0urdlul1ull0ll1ulluullldr0l1urr0lluruulluuurrrdluulurdlluruuluuluullullld*2rullld*0rulu1u0rruu*1rul1rruuruu*0r0uu1dluulurdlluull0luuluullldr1uruldruur0rruurruulur1uu*2rull0ullldruuruurruurru*1ldrr1*0ldld0rrr1drdrululurrr0r1r0ull1rurruu*1rdlulll0lluruu*0r1urrruu0*0ruu)| +|[Please add animations](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&17&19?*z0*V01*z005*605*f03*Z02*B0222*40242*C0111*60/s0?159&158&139&120&121&122&103&84&83&82&81/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&19?*z0*V01*z005*605*z0*G02*B0222*40242*C0111*60/s0?159&158&139&120&121&122&103&84&83&82&81/f0?224/#replay=nmGTi8PB&dd)| +|[The Ordeal](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&23&29?*Q1*02*30124001*20*02112*60122201*50211*701*001*6011*701*001004*3011*701*001*6011*402001*001*20110011*70122001*6011*70123001*6011*701*001*20110011221001*10102221*50111*6011*001*6011*701*001*60111001*30122021*401211*50101*00111*4011*701*001*6011212021011001*001*301221100202*201*001001*301100242*101100101*601100222*201*001*20122211*401001*00111*4011*701*00111*40*Q1/b0?188&194&182/b1?596&588&604/s0?620&619&618&617/s2?632&631&630&629/s1?625&624&623&622/)|[thejoshwolfe](https://github.com/thejoshwolfe)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&23&29?*Q1*02*30124001*20*02112*60122201*50211*701*001*6011*701*001004*3011*701*001*6011*402001*001*20110011*70122001*6011*70120001*6011*701*001*20110011221001*10102221*50111*6011*001*6011*701*001*60111001*30122021*401211*50101*00111*4011*701*001*6011212021011001*001*301221100202*201*001001*301100242*101100101*601100222*201*001*20122211*401001*00111*4011*701*00111*40*Q1/b0?188&194&182/b1?596&588&604/s0?620&619&618&617/s2?632&631&630&629/s1?625&624&623&622/f0?246/#replay=nmGTi8PB&2rrrulll0uulllddll1ululluuruuru0uuu2llluuluuurrdruruuuruuuruuldddl1rulld2u1dr2u1uu0rruurruuruu*0luu2ruuuruuuruuurullurrdldd*2luuluuuruuuluururullddrru0*1luuulu*0ruu2rruuuruuuruuuruuuru*3ldr0luuulurrrullldrrr2rruuuruuuruuuruuuru*0luuuru*0l0urruu2ld*1ruuuruuuruuuru*0luuuru*0ldr0lu*0rdlluruuuru*0lullddrrdrrrulllul2ddluuluuuruuuruuu0*0luuulurrruuulurrrullldrrr2rddd0urr1luu0dddr1rur0uulldddrrruuluru2luuulluuurrdr0ruulluurrdddl1uluu0u2ruuuruuuru*0lurrdlllu1ul2ul*0urru1l2u1u0uluu2luuuluuurrrdlluuluuuruuuluurrdlluruuul1ururruuu0ruuuru*0lu2uuu0lddrruru*0ldrru2*1ruuuruuuruuuru*0l0*0lu*2ruuruuuruu*1luuur2uu0rulldrrruuruuuruuluurddluu2lurur1ll2rdll0ruullldl2ddrrrullldl0llddr2dldldrrr0rrrdllullddd2ruuuruuuruuuru*3l*0u)| +|[Coral Block](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&17&31?*X01*z0*z0*A04*z0*l03*Z02*z0*j02*z0*30/b0?6&68&36&67&65&128&161&224&254&190&189&221&252&253&316&346&313&344&345&315&379&348&317&287&320&289&227&228&196&102&101&39&40&71&72&135&167&199&168&136&104&73&133&164&195&258&288&318&285&223&193&162&130&129&97&66&5&4&3&2&1&32&31&62&93&94&124&155&156&187&218&217&249&250&280&311&310&341&372&373&404&435&434&466&499&500&438&406&405&437&471&472&473&474&475&506&507&508&509&478&479&448&419&389&360&391&390&420&450&449&355&325&203&263&262&232&201&202&234&265&296&297&327&326&356&386&417&416&513&512&515&516&485&486&487&518&519&520&521&522&492&523&524&525&494&463&464&433&402&371&370&338&400&430&490&459&456&457&458&428&429&399&369&340&309&278&247&216&185&154&123&122&91&29&30&28&27&90&120&89&88&87&56&25&24&54&23&22&21&207&236&205&206&176&145&210&240&209&242&336&366&335&303&334&395&394&364&333&305&274&243&245&244&211&179&148&149&116&147&146&114&113&143&142&112&83&52&51&50&19&18&79&109&78&48&17&16&15&45&107&76&75&14&13&12&11/s8?443&442&441/s7?412&411&410&409/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*X01*z0*z0*A04*z0*z0*M02*z0*j02*z0*30/b0?6&68&36&67&65&128&161&224&254&190&189&221&252&253&316&346&313&344&345&315&379&348&317&287&320&289&227&228&196&102&101&39&40&71&72&135&167&199&168&136&104&73&133&164&195&258&288&318&285&223&193&162&130&129&97&66&5&4&3&2&1&32&31&62&93&94&124&155&156&187&218&217&249&250&280&311&310&341&372&373&404&435&434&466&499&500&438&406&405&437&471&472&473&474&475&506&507&508&509&478&479&448&419&389&360&391&390&420&450&449&355&325&203&263&262&232&201&202&234&265&296&297&327&326&356&386&417&416&513&512&515&516&485&486&487&518&519&520&521&522&492&523&524&525&494&463&464&433&402&371&370&338&400&430&490&459&456&457&458&428&429&399&369&340&309&278&247&216&185&154&123&122&91&29&30&28&27&90&120&89&88&87&56&25&24&54&23&22&21&207&236&205&206&176&145&210&240&209&242&336&366&335&303&334&395&394&364&333&305&274&243&245&244&211&179&148&149&116&147&146&114&113&143&142&112&83&52&51&50&19&18&79&109&78&48&17&16&15&45&107&76&75&14&13&12&11/s8?443&442&441/s7?412&411&410&409/f0?299/#replay=nmGTi8PB&7rrru8urrurr7lluuurrruuu8u7ruu*0rdddrrddluuluuu*0lddlldldddruuuruu8uruu*0rddrddr7ruluuruu*0rdddrrdrrddlddrrrurruruururuullluurrrddllddldlld*1lddllurrulldrruur8rdrrrurruruurr7*0rurruruurr8uullu7uuulul)| +|[Adventure](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&20&27?104110010*4100*21011011*0011002000*01*00*0101*0011*601011*30100110001020102*002010001000101010100010001201100102012111000121211201*201*20101100011100010201101012010111*20111*401*0020001001*101010120101011210101*0021001*40101001*7011002210101210010221201202001200010001110111*101*101001011121100021011101002111*3011001*2010110110110210001*201010001*0011*2011*001*10111001001*A01*402*00120001*101*10100100011*T0100/s0?137&110&111&112/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&20&27?104110010*4100*21011011*0011002000*01*00*0101*0011*601011*30100110001020102*002010001000101010100010001201100102012111000121211201*201*20101100011100010201101012010111*20111*401*0020001001*101010120101011210101*0021001*40101001*7011002210101210010221201202001200010001110111*101*101001011121100021011101002111*3011001*2010110110110210001*201010001*0011*2011*001*10111001001*A01*402*00120001*101*10100100011*T0100/s0?137&110&111&112/#replay=nmGTi8PB&dllddrrruurrddrrdd*0ruluuu*0lddlldllddrruulurrruu*0rdddlldd*1ruurrddrrruruuulururrddrrrdlluluulldddldllluulluulurrruuuru*0lullurrdd*1luulluullddllluurruurrururuulddldlluluuur)| +|[Sky Grid](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&15&15?40*74044300030003000344*9044002000200020044*9044300030003000344*10202*1044002000300020044*10202*1044300030003000344*9044002000200020044*90443000300030003*C4/s1?13/s0?1/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&15&15?40*74044*9044*9044002000200020044*9044*9044*10202*1044002*3020044*10202*1044*9044*9044002000200020044*9044*90*C4/s1?13/s0?1/f0?16/f1?20/f2?24/f3?28/f4?76/f5?80/f6?84/f7?88/f8?112/f9?136/f10?140/f11?144/f12?148/f13?196/f14?200/f15?204/f16?208/#replay=nmGTi8PB&dd1ddd0d*0r*1u1*0l*0uruulu0lurruur1l0rruuu1ur0uu1*0u0ur*1ullluuulluuul*0d*0r1ruull0r1urruuul0uu1*1l0u1urrddl0ll1ldlll0llldrddd*4r1d)| +|[Block Train](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&7&31?*F02*O020002202020004*C0202*402*702*902*202*C02*402*002*S0*31*H2111/b0?159&163/s0?127&126&125&124/s3?158&157&156&155/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&7&31?*F02*O020002202020004*C0202*402*702*902*202*C02*402*002*S0*31*H2111/b0?159&163/s0?127&126&125&124/s3?158&157&156&155/#replay=nmGTi8PB&3ur0rrullld*5rurrr3r0rrdrrulluru3u*2r0llurrdl3u0l3rrur0lllu*1ru3uu*0lu*0rddll0rullur3l0r3ll0urd3u0rdrr3rruurrrdrr0urr3rdrr0rrr3rr*0u0rr*0u)| +|[Turn Around](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&9&14?*A01*90111*70*112*40100011*40104001*401*001*40111*70*210012*00/s0?103&102&88&74/s1?101&87&73&59/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&9&14?*A01*90111*70*112*40100011*40104001*401*001*40111*70*210012*00/s0?103&102&88&74/s1?101&87&73&59/#replay=nmGTi8PB&rrruu1rrruruuruulddldl0luurddl1luul0llluull)| +|[Turn Around 2](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&9&14?*A01*90111*70*112*40100011*40104001*401*001*40111*70*21012*10/s0?102&88&74/s1?101&87&73/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&9&14?*A01*90111*70*112*40100011*40104001*401*001*40111*70*21012*10/s0?102&88&74/s1?101&87&73/#replay=nmGTi8PB&rrruu1rrr0lurdl1ruruldlllulu0*0lulu)| +|[There and Back Again](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*z0*z0*p04011*A0*51*z0*z0*z0*g01*A0*21*602*101*001000*A1002*101*001/b1?403&435&467&437&407&375&343&373&405/b0?479&293/s0?445&444&443&442/f0?17/f1?30/s5?476&475&474/)|[gavinksong](https://github.com/gavinksong)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*z0*z0*p04011*A0*51*z0*z0*z0*g01*A0*21*602*101*001000*A1002*101*001/b1?403&435&467&437&407&375&343&373&405/b0?479&293/s0?445&444&443&442/s4?476&475&474/f0?17/f1?30/#replay=nmGTi8PB&u*3lu4ullullulluulululld*6r0ur4rrullddrrru0ruulll4ldrru0u4rdruu0lldrrr4l0ruuu4lurulddl0lulullldrrulldddrr4u0ruur4l0uulurull4lluu0uuurururruururrrdllul*0urddlllulld*1rdllulldlu4rrruur0l*0u4ulur0r4r0*0u4ulurr0r*0u4uur0rrrdll4ulurrddllu0uulul*0urrulur4lurdr0u4r0uuluruuu*5rulluurrru*0ruu*2ldddrruu*Aldd4uruul0rrurruuu4ldd0ulllurrruuu4ruu0lldddr4l0ruuu4lur0uuru4urul0lu4uu0u4rr0*5ruu4ulld*4r0u4r0r*0uluuruull4ur0uu*1r4*2rdd0rd)| +|[You Don't Have To Wait For Animations](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&16&15?*K1000*51301*10*3100102020*3100102224*3100100022*31*40*310122*00*11*005*1011*205*201101*50101101*5210110*71011*9011*9011*901/b0?102&42/s0?137&136&151&166&181/)|[thejoshwolfe](https://github.com/thejoshwolfe)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&16&15?*K1000*51001*10*3100102020*3100102224*3100100022*31*40*310122*00*11*005*1011*205*201101*50101101*5210110*71011*9011*9011*901/b0?102&42/s0?137&136&151&166&181/f0?36/#replay=nmGTi8PB&*2ruuuluuu*2l*0u*3rdddlulurulurruululuuull*0urrdrrdd)| +|[Keyhole](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&12?*z0*L02*702*702*702*702*702*50402*702*702*702*702*702*q0*21*20*21*20*21000222*21222/b0?256&244&232&233&234&246&258&257&269&65&66&67&68&64&63&62&61/s1?184&185&197&196/s2?208&209&221&220/f0?128/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&12?*z0*L02*702*702*702*702*702*50402*702*702*702*702*702*q0*21*20*21*20*21000222*21222/b0?256&244&232&233&234&246&258&257&269&65&66&67&68&64&63&62&61/s1?184&185&197&196/s2?208&209&221&220/f0?128/#replay=nmGTi8PB&1lddd*0rull2lu*0r1u2rruuldl1rrrurruuulluuu2uuu1u2*2luur1luuurrrd*1lu2rur1rrru*3luuu2rrruuu1r*0uru2luuu1*0u)| +|[Block Train 2](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&7&27?*K20002*M02*602*B02*6020002*50402*302*E02*M0*K2000/b0?30&31&29&137&138&139/s0?58&57&56&55/s3?85&84&83&82/s2?112&111&110&109/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&7&27?*K20002*M02*602*B02*6020002*50402*302*E02*M0*K2000/b0?30&31&29&137&138&139/s0?58&57&56&55/s3?85&84&83&82/s2?112&111&110&109/#replay=nmGTi8PB&3rr0rrru*2lururu2rrr0rrr3rrr2urrdrr0rrr3rd2rrul3r0ur3r0u2lu3r0urr3rrr2r0rrr2r3r0rdru2uurr3rrr0r2urrr0*2r2*2r3u*1r0ur)| +|[Fruit Maze 2](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*z0*f0111000111*H010001110001*D04*001*10101*G010001010001*H0101000101*I0100010001*J01011101*J0100010001*I0101000101*H010001010001*G0101*10101*G010001110001*H0111000111*W0/f0?141/f1?143/f2?147/f3?149/s1?172&171&170&169/f4?176/f5?203/f6?205/f7?209/f8?211/f9?235/f10?237/f11?238/f12?239/f13?241/f14?267/f15?268/f16?270/f17?271/f18?298/f19?302/f20?329/f21?330/f22?332/f23?333/f24?359/f25?361/f26?362/f27?363/f28?365/f29?389/f30?391/f31?395/f32?397/f33?424/f34?451/f35?453/f36?457/f37?459/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*z0*f0111000111*H010001110001*D04*001*10101*G010001010001*H0101000101*I0100010001*J01011101*J0100010001*I0101000101*H010001010001*G0101*10101*G010001110001*H0111000111*W0/f0?141/f1?143/f2?147/f3?149/s1?172&171&170&169/f4?176/f5?203/f6?205/f7?209/f8?211/f9?235/f10?237/f11?238/f12?239/f13?241/f14?267/f15?268/f16?270/f17?271/f18?298/f19?302/f20?329/f21?330/f22?332/f23?333/f24?359/f25?361/f26?362/f27?363/f28?365/f29?389/f30?391/f31?395/f32?397/f33?424/f34?451/f35?453/f36?457/f37?459/#replay=nmGTi8PB&1drddrruruurrurrddlddlddrddrddllulluululuuluuluurrdrrddrdrddrddrddllu*0ldlluuruuruuluuluurrd*0rurrddlddlddldlddlldlluuruuruuluuluurrd*0rurrddlddlddrddld*0ldlluuruuruuluuluurrd*0rurrddlddlddrddrddllu*0luluuruuluuluurrd*0rurrddlddlddrddrddllu*0ldlluuruuruuluuru*0rurrddlddlddrddrddllu*0ldlluuruuruuluuluurrd*0rdrddlddrddrddllu*0ldlluuruuruuluulu*0l)| +|[Tight Space](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&14&21?*D02*G02*G02*G02*601*b0*72*5052002*60*42002*G02*B04*002*G0*12*F052*20*71*02*20/s2?28&27&26&25&24&23&22&21/s1?49&48&47&46&45&44&43&42/s0?70&69&68/f0?102/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&14&21?*D02*G02*G02*G02*601*b0*72*5052002*60*42002*G02*B04*002*G0*12*F052*20*71*02*20/s2?28&27&26&25&24&23&22&21/s1?49&48&47&46&45&44&43&42/s0?70&69&68/f0?102/#replay=nmGTi8PB&1rrruu*2l2rrru*0l0ul2ldd*1r0ll2u*2l0*0luu*2r2uurrru*0rdrruu*0l0u*0l2uull0l1u0lur1ururr0u*2r1uru*1rddlllul0*0ru*1ld1l0rurulld1l0ru*1rdrrruulllu*1lu*9luu1lluu*6luull2*3luull)| +|[Floating Fruits](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&10&9?*804*v02*012*60/f0?24/f1?37/f2?43/s0?69&68&67&66/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&10&9?*804*v02*012*60/f0?24/f1?37/f2?43/s0?69&68&67&66/#replay=nmGTi8PB&uuurulldluurr*1ulddlluullurrrdruull*2u)| +|[Skyscraper](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&20&28?*z0*004*z0*z0*z0*z0*z0*z0*C0*810110*K1*00*a1/b0?429&430&458&457/b1?432&460&459&431/b2?433&461&462&434/b3?463&435&436&464/b4?466&465&437&438/s0?407&406&405&404/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&20&28?*z0*004*z0*z0*z0*z0*z0*z0*C0*810110*K1*00*a1/b0?429&430&458&457/b1?432&460&459&431/b2?433&461&462&434/b3?463&435&436&464/b4?466&465&437&438/s0?407&406&405&404/#replay=nmGTi8PB&*0rd*0lddllluuluuluru*3lddrruu*1ruu*0rdddllluuuluuluru*1lddrruurrruuruurrrdddllluuluulurulllddrruurruu*1rulluulurrdlddllluululurrddrrruuruulluuluulluuuruur*0u)| +|[Fruit Maze 3](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&16&12?*114*4141000*31*2014*01*401114001*10*01*404111*301114*001*1011*601*704*01*30*11001000*114*00*4101004*214000*614*21/f0?16/f1?17/f2?18/f3?26/f4?27/f5?28/f6?29/f7?30/f8?31/f9?38/f10?39/f11?40/f12?41/f13?42/f14?43/f15?44/f16?45/f17?50/f18?51/f19?53/f20?54/f21?55/f22?56/f23?57/f24?62/f25?63/f26?64/f27?65/f28?66/f29?67/f30?68/f31?69/f32?74/f33?75/f34?76/f35?77/f36?78/f37?79/f38?80/f39?85/f40?86/f41?87/f42?88/f43?90/f44?91/f45?92/f46?93/f47?94/f48?97/f49?98/f50?99/f51?100/f52?101/f53?102/f54?103/f55?104/f56?105/f57?106/s0?108/f58?109/f59?110/f60?111/f61?112/f62?113/f63?114/f64?115/f65?116/f66?117/f67?118/f68?124/f69?125/f70?126/f71?127/f72?128/f73?129/f74?130/f75?136/f76?137/f77?139/f78?140/f79?141/f80?148/f81?149/f82?150/f83?151/f84?160/f85?162/f86?163/f87?172/f88?173/f89?174/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&16&12?*114*4141000*31*2014*01*401114001*10*01*404111*301114*001*1011*601*704*01*30*11001000*114*00*4101004*214000*614*21/f0?16/f1?17/f2?18/f3?26/f4?27/f5?28/f6?29/f7?30/f8?31/f9?38/f10?39/f11?40/f12?41/f13?42/f14?43/f15?44/f16?45/f17?50/f18?51/f19?53/f20?54/f21?55/f22?56/f23?57/f24?62/f25?63/f26?64/f27?65/f28?66/f29?67/f30?68/f31?69/f32?74/f33?75/f34?76/f35?77/f36?78/f37?79/f38?80/f39?85/f40?86/f41?87/f42?88/f43?90/f44?91/f45?92/f46?93/f47?94/f48?97/f49?98/f50?99/f51?100/f52?101/f53?102/f54?103/f55?104/f56?105/f57?106/s0?108/f58?109/f59?110/f60?111/f61?112/f62?113/f63?114/f64?115/f65?116/f66?117/f67?118/f68?124/f69?125/f70?126/f71?127/f72?128/f73?129/f74?130/f75?136/f76?137/f77?139/f78?140/f79?141/f80?148/f81?149/f82?150/f83?151/f84?160/f85?162/f86?163/f87?172/f88?173/f89?174/#replay=nmGTi8PB&ruurddrurululuruluurdrrulurrdrdldldldrrurururddldldldldl*1drrurulluururururrdldldldrrurur)| +|[Fruit Maze 4](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&12&10?1114*4100114*01*30111*30411*00100114001*10110001*0011*4041001*00114*304*014110*91/s0?106/f0?12/f1?13/f2?21/f3?22/f4?23/f5?24/f6?25/f7?26/f8?27/f9?31/f10?32/f11?33/f12?34/f13?35/f14?36/f15?37/f16?41/f17?42/f18?43/f19?44/f20?46/f21?47/f22?51/f23?52/f24?54/f25?55/f26?56/f27?57/f28?58/f29?61/f30?62/f31?63/f32?65/f33?66/f34?67/f35?68/f36?71/f37?72/f38?73/f39?74/f40?75/f41?76/f42?77/f43?78/f44?81/f45?82/f46?84/f47?85/f48?86/f49?87/f50?91/f51?92/f52?93/f53?94/f54?95/f55?96/f56?97/)|[XeroOl](https://github.com/XeroOl)| +|[Fruit Maze 5](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&11&14?*O0*B1*001*3011*001*3011*001*3011*004*30*31*301*101*301*101*301*10*51/s0?88&87&86&85&71&57&43&44&45&46/b5?65/b10?67/b15?91/b20?93/b25?95/b30?123/b40?121/b35?119/b0?63/f0?49/f1?51/f2?53/f3?62/f4?64/f5?66/f6?68/f7?77/f8?78/f9?79/f10?80/f11?81/f12?90/f13?92/f14?94/f15?96/f16?105/f17?106/f18?107/f19?108/f20?109/f21?118/f22?120/f23?122/f24?124/f25?133/f26?135/f27?137/)|[XeroOl](https://github.com/XeroOl)| +|[Fruit Maze 6](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&13&17?*I0*71*201*501*201*501*201*5010*21*501014*9010*21*501*201*501*201*501*201*501*20*71*E0/b0?59&58&75/b5?61/b10?63&81&64/b15?94/b20?96/b25?109/b30?115/b35?128/b40?130/b45?143&160&161/b50?163/b55?165&166&149/s4?107&106&105&104/f9?62/f28?116/f37?145/f17?92/f8?60/f12?77/f18?93/f24?110/f25?111/f26?113/f27?114/f43?164/f42?162/f31?127/f30?126/f16?91/f11?74/f7?57/f0?41/f1?42/f2?43/f3?44/f4?45/f5?46/f6?47/f10?65/f15?82/f22?99/f21?98/f20?97/f14?79/f13?78/f19?95/f32?129/f38?146/f39?147/f33?131/f34?132/f35?133/f40?150/f44?167/f51?183/f50?182/f49?181/f48?180/f47?179/f46?178/f45?177/f41?159/f36?142/f29?125/f23?108/)|[XeroOl](https://github.com/XeroOl)| +|[Disarm](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&13&17?*I0*71*201*501*201*501*201*5010*21*50104*A010*21*501*201*501*201*501*201*501*20*71*E0/s0?107&106&105&104&103/b0?95&129/b1?113&111/b2?93&97/b3?131&127/b4?145&77/b5?147&79/f0?112/f2?130/f4?94/f3?96/f7?78/f1?128/f12?146/f9?114/f8?80/f6?76/f5?110/f10?148/f11?144/f13?126/f14?92/f15?60/f17?62/f16?98/f18?132/f19?164/f20?162/f21?160/f22?166/f23?64/f24?58/f26?57/f27?74/f28?91/f29?108/f30?125/f31?142/f32?159/f33?176/f34?177/f35?178/f36?179/f37?180/f38?181/f39?182/f40?183/f41?184/f42?167/f43?150/f44?133/f45?116/f46?99/f47?82/f48?65/f49?48/f50?47/f51?46/f52?45/f53?44/f54?43/f55?42/f56?41/f25?40/)|[XeroOl](https://github.com/XeroOl)| +|[Level 1](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&30?*z0*z0*O04*z0*z0*z0*z0*X01*z0*z000*11*z0*U0*31*z0*f0/s2?513&543&573&603&633&663/s0?634&664&665&666/s1?667&668&669&670/b0?559&563&501&621/)|[DoctorEndugu](http://steamcommunity.com/app/357300/discussions/0/620713633849185372/?ctp=2#c350542683202995503)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&30?*z0*z0*O04*z0*z0*z0*z0*X01*z0*z000*11*z0*U0*31*z0*f0/s2?513&543&573&603&633&663/s0?634&664&665&666/s1?667&668&669&670/b0?559&563&501&621/#replay=nmGTi8PB&rrdrru*1ruulll2*1rurrru*3ruururruu*1rulllullullulldllul0ul2*0l1lllu0lurrddluuu1rru0l2ldlluluurrrdl*0dl*0urulu*0ru*0l0urruu1urruuulluuluurr2u0luuulluuluurr2*0ull*0urrrddl0rruul1rullddru2l1ruu2*0u0uurrrullululuurddlu1lddr2r1r0ulu2*2rull0urrr1rr2uluuu1ul0uul2uuu)| +|[Level 2](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&30?*z0*z0*z0*z0*z0*z0*J02*z0*Y04*b0222*01*c0*21*W0101010101*g0*02*z0*W0/b0?383&443/s0?627&626&625&624/s1?533&534/)|[DoctorEndugu](http://steamcommunity.com/app/357300/discussions/0/620713633849185372/?ctp=2#c350542683202995503)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&30?*z0*z0*z0*z0*z0*z0*J02*z0*Y04*b0222*01*c0*21*W0101010101*g0*02*z0*W0/b0?383&443/s0?627&626&625&624/s1?533&534/#replay=nmGTi8PB&uluuululuul1lurr0lldr1ul0r1ll0r1l0u*0rddlll1urrrd*0l0*0l1*0l0ldll1ll0uurull1lll0*2l1u*1l0u1l0ull)| +|[Bumpy Road](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&15&30?*z0*z0*z0*z0*z0*t04*10220022002200220022002200220022112211221122112211221122112211/b0?335/b1?365/s1?277&276&275&274&273&272/s0?307&306&305&304&303&302/s2?247&246&245&244&243&242/)|[XeroOl](https://github.com/XeroOl)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&15&30?*z0*z0*z0*z0*z0*t04*10220022002200220022002200220022112211221122112211221122112211/b0?335/b1?365/s1?277&276&275&274&273&272/s0?307&306&305&304&303&302/s2?247&246&245&244&243&242/#replay=nmGTi8PB&uull1u*0lddrruuul2u*0ldddr1u2r1uuu2rr1rrr2ull0luurrrdlll2u1rru*2ldrr0u1r0l1uu*1r0lll2*0r0ul2r1ru*0luullld*1rulll0ul1ulllddrru*6r0lu*0rddlll1u*2lu*1rur2*2rurrru*1rddd1rruu*0rddd0u*2r)| +|[Level 0 "Checkmark Underpass"](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&17&31?*t1000*L1*20*D1*A0*61*H0*41*J0*41*J0*51*I011100*31*101*9011100*01*701*6011100111*201*C01100011*803*70110*01*101*F010*02*50111222*601*30111*503*6011*001000*812*B04*I0/b0?417&418&388&358&359&328&416&385&329/b1?344&473&474/s1?414&413&412/s2?228/)|Teal Knight||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*t1000*L1*20*D1*A0*61*H0*41*J0*41*J0*51*I011100*31*101*9011100*01*701*6011100111*201*C01100011*K0110*01*101*F010*02*50111222*601*30111*G011*001000*812*B04*I0/b0?417&418&388&358&359&328&416&385&329/b1?344&473&474/s1?414&413&412/s2?228/f0?360/f1?455/#replay=nmGTi8PB&1rdrruuldl2rlrrr1ur2rrr1uururrrdll2r1uuldldllddr2lll1r2l1u2*1l1llluuruu*3rurrrdd*6lu*1ld*1luuururuulddlddd*2rdd)| +|[Level 1 "Hanging spikes"](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*R10*51*40*91001000111*80*61*J011100111*001*3010111*301000111*202*0022002202*101000111*G02*4011*805*101*6011*I04*2011*705*202*6011*P011*20202*0020002*801*Q01*B02*z0*d0/b1?263&294&325&356&387&379&196&195&164&133&134&132&131/s0?255&254&285&316/s2?66&97/f3?266/f0?102/b2?348&317&286/f1?198/f2?233/)|Teal Knight||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*R10*51*40*91001000111*80*61*J011100111*001*3010111*301000111*202*0022002202*101000111*G02*4011*805*101*6011*I04*2011*705*202*6011*P011*20202*0020002*801*Q01*B02*z0*d0/b1?263&294&325&356&387&379&196&195&164&133&134&132&131/s0?255&254&285&316/s2?66&97/f3?266/f0?102/b2?348&317&286/f1?198/f2?233/#replay=nmGTi8PB&*2rullu*1lurru2*5rddrr0r2r0rddll2r0ulllurr2d0rd*0r2rrrd0r)| +|[Level 2 "Trap Mine"](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&17&31?*z0*z0*q0*21*H0*81*D0*C1*90*G1*50*D1*305*105*304*K101010*M121212*z1*x1/s1?318/b0?323&321&319/)|Teal Knight||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*z0*z0*q0*21*H0*81*D0*C1*90*G1*50*D1*305*105*304*K101010*M121212*z1*x1/s1?318/b0?323&321&319/#replay=nmGTi8PB&1*5rl*5rl*4rl*5r)| +|[Level 3 "The Servant"](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&17&31?*Y101010*L1*60*G1*70*G1*401300*710*31202020202110*7100*31*4011*70100*31*H0100*31*401*80100*21*601*A0*21*601*70100*21*I0100*21*I0100114*O0*0101121212121222122121122212*C1*101100*Z1/b0?425&394&487/b1?363/b2?332/b3?301/b4?316&347&378&409&379/b5?264&265&266&267&268&269&270&271&272&273&274/b7?420&481/s0?426&427&428&397&366&335&336/s2?98/s11?42/s7?40/s3?38/b6?405&139&231&129&74&75&76&73&71&69&400&369&338/s5?152&183&214&245&276&307/)|Teal Knight||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*Y101010*L1*60*G1*70*G1*401000*710*31202020202110*7100*31*4011*70100*31*H0100*31*401*80100*21*601*A0*21*601*70100*21*I0100*21*I0100114*O0*0101121212121222122121122212*C1*101100*Z1/b0?425&394&487/b1?363/b2?332/b3?301/b4?316&347&378&409&379/b5?264&265&266&267&268&269&270&271&272&273&274/b7?420&481/s0?426&427&428&397&366&335&336/s2?98/s11?42/s7?40/s3?38/b6?405&139&231&129&74&75&76&73&71&69&400&369&338/s5?152&183&214&245&276&307/f0?138/#replay=nmGTi8PB&*1ulldd*4ld*1rurruuururrdrrdllluruluruluurul*0u*0ldddrurdrurulllurrulurru*0ld*5lululuul2r0u*4r2*4r0*0r2*0r0uurrddr2rrr*0l0uur2r0rr2rr0uuur2rr0uurrulll*0d*0luu*4luuluull*0d*3r*0urrddrrdd*1ru*0ld2*1l0lu2*0l0ulldlul2l0u2l0uulll*1drr2uu0uuu2r0uurrdddrddrurulldluuuru*1lu*1rdd*2ru*3l*0ulllddlddrr*0urrrdd*2rullldlululddl2lr0uul2rl0u2rr0ruluulllu*0r*1dr2l0uuuldl2ll0uu2l0uulllurrr*0d*0r2rr*1lrrr0ulll2lll0ul2l0uu2l0*0rdd*0l*1u2l0u2rr0*2ru*0luuulluull*0d*1r2rrr0*0ur2rr0rr*0d*1rurrdr*0urrr*0dlluuruluruluu*0ldddrurdrurulluru*0ldd*0l2r0u*0r2*0r0ur2r0urrddr2rrr*0l0rrr2rrr0uur2rr0ulldlluu*0rd*1luullluu*0l*0drrr*0urrddrrru*0rd*0l2*1l0ul2lll0ullldlul2l0u2l0uu*0l*0d*0r2r0uuu2r0uurrdddrddrurulllddrru*1rd*0lullluuu*0l*0drr*0urrrdd*2rd*0lululddl2lr0uul2rl0u2rr0ruluulllurrrdddrddr2l0urullddrurrru*0l2r0ul2l0uu2l0uulllurrr*0d*0r2rrlll0ddl2r0ll2l0uul2l0uu2l0*0rdd*0l*1u2l0u2rr0rrdd2rr0rrr2*0r0ullldluuluull*0d*0r*0urrddrrrdd*1ruuurrru*0lddd*0l2r0urrrdr2*0r0uur2rr0ulldlllulu*0rdrr*0urrrdddllurul2l0uullddlllullld*0rururdrurull2lrr0lllurrrddruuulld*1luluuull*0dr*0urrddrrdruurrrddr2lll0rr2llrr0r2r0ulll2lll0l2lll0d*0ruurru*0ldlluulldl2u0ul2l0u2l0uu*1lddd*0ruuu2r0uurrdddrddrurulldluurululllurrr*0drru*1ru*3luuu*0l*0drr*0urrrddrd*1rd*0lululddl2lr0uul2rl0u2rr0rululllurrrddrdddr2l0u*0r2r0rrd*0l2r0ulll2lll0ul2l0uu2l0uulllurrr*0drrrd2rrlrr0dll2ll0uul2l0uu2l0urrdddll*1u2l0u2rr0rrddrurullddluuluullldddrrr*0ur*1u2rrr0ulldddrrrddrd*2rururrdd*1r2dr5r*1uldd0uuu5*8luuull0u*7l5*4l0uluu*0lddldd*1l3l7u2u7*1l11*2l3rrlll2l7lll11*0l3*0l2ulld*3ld*0l0ld*0l5*1l)| +|[Level 4 "Greed that goes well"](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*81*50*I1*50*I1*50*I1*50*I1*50*I1*50*I1*004*00111000*C1*501*30*21*D01011*00*1100110011*801*10*0100*31*60111*10*01*F0111*02*112101001112*50*A10122*01*001*00*A10*31*001*00*91*901*00*910*11011*50*61/b2?257&313&256/s1?357/s2?326/s0?388/s3?295/f1?253/f11?470/b1?283&475&469/b0?512&350&351/f12?476/f0?239/f3?300/f2?258/f10?389/f4?325/f5?327/f8?358/f7?356/f9?387/)|Teal Knight||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*81*50*I1*50*I1*50*I1*50*I1*50*I1*50*I1*004*00111000*C1*501*30*21*D01011*00*1100110011*801*10*0100*31*60111*10*01*F0111*02*112101001112*50*A10122*01*001*00*A10*31*001*00*91*901*00*910*11011*50*61/b2?257&313&256/s1?357/s2?326/s0?388/s3?295/f1?253/f11?470/b1?283&475&469/b0?512&350&351/f12?476/f0?239/f3?300/f2?258/f10?389/f4?325/f5?327/f8?358/f7?356/f9?387/#replay=nmGTi8PB&lu1ru0rr2luruld1lulul2rur0ull2ul1uruu*2ruu*0ru*0ldd*2l3ll2lul0uu1lurrdddl0r1l0r1lurr0ulll3lll0ll3l2lullulu*3l3*1r1ullldrrulluldll2dlddrddd*3r1uu2r1lurrr3l1uuur3r1uulll3*1l1lulu*3l2rruruurrru*0l1dldd*6r3*1r1urr2urruluu3u1rrrdddll2ruuu0uruuuru1*2u)| +|[Level 5 "Collapse"](https://jmdiamond3.github.io/Snakefall-Redesign/#level=3tFRIoTU&17&31?*01*20*L1*405*I1*20*L1*B0134*91*B010*A1*B01*00*71*B01101*00*41*B03*00103*L10*81*50*51*505111*50*51*60111*50*51*60111*50*51*601112*2020*51*601112*2022*51*601*703004002*80*01*20101101*12*60/b0?4&407/b1?5&377/b2?6&378/b7?468&375&344&313&282/b8?478&175/b3?7&472/b4?8&442/b5?9&443/b6?35&36&37&38&39&40&42/s0?166&167&168&169&170&171&172&173&204&203&202&201&200&199&198&197&196&227&228&229&230&231&232&233&234&235/s1?41/s2?467/)|Teal Knight||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*01*20*L1*405*I1*20*L1*B0104*91*B010*A1*B01*00*71*B01101*00*41*G0100*L10*81*50*51*505111*50*51*60111*50*51*60111*50*51*601112*2020*51*601112*2022*51*601*A04002*80*01*20101101*12*60/b0?4&407/b1?5&377/b2?6&378/b7?468&375&344&313&282/b8?478&175/b3?7&472/b4?8&442/b5?9&443/b6?35&36&37&38&39&40&42/s0?166&167&168&169&170&171&172&173&204&203&202&201&200&199&198&197&196&227&228&229&230&231&232&233&234&235/s1?41/s2?467/f0?113/f1?236/f2?243/f3?477/#replay=nmGTi8PB&lldd*1lurulurulurrrdrrdrrdlldd*1lurrrulllu1r2*9r0uuu*0rdddrrdddr1ll*Arurrrdlullullluur0*6ruuluur)| +|[Level 6 "Decisions"](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*21*50*D1000111*C04111000*510*3122022*71*D02*7011*P011*P011*301*901*3011*3011*7011*3011*301*901*3011*3011100*1100111*3011*30*B1*3011*40*91*4011*P011*P01120222*F022202140011*H211004*R1/b2?6&7&8&48&9&10&11&12&13/b1?59&429&430&431/b0?33&405&406&407/s1?257/s2?269/s0?263/f11?494/f0?53/f14?52/f8?397/f10?467/f5?377/f7?236/f12?237/f6?235/f1?227/f2?228/f3?229/f4?232/)|Teal Knight||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*21*50*D1000111*C04111000*510*3122022*71*D02*7011*P011*P011*301*901*3011*3011*7011*3011*301*901*3011*3011100*1100111*3011*30*B1*3011*40*91*4011*P011*P01120222*F022202140011*H211004*R1/b2?6&7&8&48&9&10&11&12&13/b1?59&429&430&431/b0?33&405&406&407/s1?257/s2?269/s0?263/f11?494/f0?53/f14?52/f8?397/f10?467/f5?377/f7?236/f12?237/f6?235/f1?227/f2?228/f3?229/f4?232/#replay=nmGTi8PB&1ru*0ru*0ru*2l2lu*0lu*1ldr0lll2ull0ll1lullu*4ld*1ru*1lurrrur2uul0l2ull0ll2ll0ll2ll0l2dr1ruulll2r0r1dll2ull1*0d2uu0l2ruu1rrur2r1*3u2rrr1*4rdddllluul2r1ul2uluu1u2*Br0*1l1*8ruuu*5rd*1lu*1rdlddrr)| +|[Level 1](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&13&21?*z0*P04*r0111*10111*60111*10111*60111*10111*60111*10111*60111*10111*60111*10111*10/s1?98&119&140/s0?90&111&132/f4?176/f3?177/f2?180/f1?179/f0?178/)|[Cookie](https://steamcommunity.com/app/1014140/discussions/0/1814296273120173053/#c1814296273122350024)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&13&21?*z0*P04*r0111*10111*60111*10111*60111*10111*60111*10111*60111*10111*60111*10111*10/s1?98&119&140/s0?90&111&132/f4?176/f3?177/f2?180/f1?179/f0?178/#replay=nmGTi8PB&1lldldlul0*2rulll1luu*1ru*1ldd0uu1l0ll1uuur0urrr1*1rddruuru*1lu*0ruuur0uluurrdllur*0u1uulll)| +|[Level 2](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&13&14?*z0*G04*P01*221*t0/s0?73&87&101/s1?94&108/b0?59/f1?62/b1?80/)|[Cookie](https://steamcommunity.com/app/1014140/discussions/0/1814296273120173053/#c1814296273122350024)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&13&14?*z0*G04*P01*221*t0/s0?73&87&101/s1?94&108/b0?59/f1?62/b1?80/#replay=nmGTi8PB&lurruruurullldrrurr1l0rrurrd*2lurrdr1u*3lull0uull)| +|[Level 3](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&11&19?*a04*t0111*10111*40111*2011*40111001*90*71*40*71*40*71000/b0?81&85/s0?89&90/s2?70&71/f0?147/f2?41/f1?42/)|[Cookie](https://steamcommunity.com/app/1014140/discussions/0/1814296273120173053/#c1814296273122350024)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&11&19?*a04*t0111*10111*40111*2011*40111001*90*71*40*71*40*71000/b0?81&85/s0?89&90/s2?70&71/f0?147/f2?41/f1?42/#replay=nmGTi8PB&ll2lll0ulu2u*0lullu*0ru*0rul0rul2luu0lll2rru*0luu0llurrurrrul2rul0lu2uu*0lulu*3rdrd*1ruuu*0ldd0rur2dl0rul2ulll0ll2*0u*0l0*2l2llu)| +|[Level 3 2](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&11&19?*p04*e0111*1011*50111*1011*50111*C01110*21*50*61*50*61*00/b0?87&83/f0?147/f2?41/f1?42/s0?45&64/s2?49&68/)|[Joel Fox](https://joelthefox.github.io/)|Derived from Cookie's level above|☑| +|[Balancing Act](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*01*M011011*J0*11*N0*0101110001*G01110111*L011011*M011*P011*P01101*N0*01*9011*80*11*70*01*101*10*11*70*0100*01*10*01*101001*0011*0011*20111*201001*704*20111*201001*402*50111*201001*701*20111*201001*701*201/b0?299&294/f0?416/f3?153/b1?390&219&188/s0?64&63&32/s1?265&266&297/s2?28&29/f1?148/)|[IHNN](https://steamcommunity.com/id/IHNN/)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&31?*01*M011011*J0*11*N0*0101110001*G01110111*L011011*M011*P011*P01101*N0*01*9011*80*11*70*01*101*10*11*70*0100*01*10*01*101001*0011*0011*20111*201001*704*20111*201001*402*50111*201001*701*20111*201001*701*201/b0?299&294/f0?416/f3?153/b1?390&219&188/s0?64&63&32/s1?265&266&297/s2?28&29/f1?148/#replay=nmGTi8PB&1u*2rurr2*0l1ulluuruu2u1ullddlll2*0l1ul2u*1lur1ullu*5l0*6r1u*0ruuu0*0rul2r1rulluu0l2r0ld2u0r2*0l1rr2ll1ruuluuulu*1r0ur1*1r0*1r1rr0urdrrrulllulldrrrurrull1uluruuu*2r*0u*1l0urd1*1l0*1l1ul0ulll1ulu*2l0*4l1*1l2u*0l1u2u1r2l1rr0lllurrrdrdrru1r0llu2llur0*0lull2*0r0urrruur1uu2ul0rul1ululu0ul2ll0ul1u2*1lur0ur1rrr0*0rdd2urr0r1rrdruuuldlullddlllurrr0u*2l2*0r0ur1r2*0r0urrr1uuururrullldddluur0rulldrrur1ululllu0rulldrurr1*0rddldluuluuurr2*1r1rrurrrdrdddrdrd*0ru2*2r0rrddrdrrr1ll)| +|[Temple](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&20&40?*b1*A0*31*D0110*32*40111*70*3201102*102*I02*10201102022202*30*02*70202220201102024202*I0202420201100020002*401*902000200011000*12*30*02*70*1200011*Y0*01*W0*01*U0*21*U0*21*U0*21*U0*21*V0*11*202*O0*11*202*N0*212*102*N0*81222*410*510*j1/f25?325/f26?483/f27?526/f10?569/f0?652/s4?705/f8?670/f11?550/f6?220/f12?258/f1?196/f4?238/f2?665/b3?612/b4?625/f3?255/f5?138/)|[Joel Fox](https://joelthefox.github.io/)| +|[Renovated Temple](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&20&40?*b1*A0*31*D0110*32*40111*70*3201102*102*I02*10201102022202*30*02*70202220201102020202*I0202020201100024002*401*902040200011000*12*30*02*70*1200011*Y0*01*W0*01*U0*21*U0*21*U0*21*U0*21*V0*11*202*O0*11*202*N0*212*102*N0*81222*410*510*j1/f25?325/f26?483/f27?526/f10?569/f0?652/s4?705/f8?670/f11?550/f6?220/f12?258/f1?196/f4?238/f2?665/b3?612/b4?625/f3?255/f5?138/)|[Joel Fox](https://joelthefox.github.io/)|Addresses a common criticism of Temple|☑| +|[Basilica](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&49&40?*b1*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*70*81*B011*Y011*40*910111*9011*50*810111*90110*320*810111*901102*102*40111*80*2201102022202*O0201102024202*30*02*3020*12020201102020202*E02020002020201102020202*301*602020202020001102000202*30*02*30202020202000110*12*G02024202*1011*M02022202*1011*M02002002000*01*M02200022000*0102*L0*12*00*01*W0*01*X0111*3022*O0*01*2022*N0*11*020022*N0*81222*A10*n1/b0?1102&1103/b1?1772/b2?1785/f23?64/f0?358/f5?1161/f3?1121/f2?1081/f7?1222/f6?1182/f4?1142/f15?1417/f8?1297/f9?1298/f11?1380/f14?1415/f19?1729/f12?1398/f10?1356/f13?1409/f17?1686/f16?1643/f18?1710/f20?1750/f21?1812/f22?1825/s0?1865/)|[Gooby](https://github.com/jmdiamond3)|Based on Joel's levels above|[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&49&40?*b1*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*Y011*70*81*B011*Y011*40*910111*9011*50*810111*90110*320*810111*901102*102*40111*80*2201102022202*O0201102024202*30*02*3020*12020201102020202*E02020002020201102020202*301*602020202020001102000202*30*02*30202020202000110*12*G02024202*1011*M02022202*1011*M02002002000*01*M02200022000*0102*L0*12*00*01*W0*01*X0111*3022*O0*01*2022*N0*11*020022*N0*81222*A10*n1/b0?1102&1103/b1?1772/b2?1785/f23?64/f0?358/f5?1161/f3?1121/f2?1081/f7?1222/f6?1182/f4?1142/f15?1417/f8?1297/f9?1298/f11?1380/f14?1415/f19?1729/f12?1398/f10?1356/f13?1409/f17?1686/f16?1643/f18?1710/f20?1750/f21?1812/f22?1825/s0?1865/#replay=nmGTi8PB&uru*Alurulu*Er*0u*Eluuluu*0lu*0ldlluu*1rdruuluuruuurr*3u*Nruurul*1urruuulddllur*4uruluurrdddllluruurruuldll*3d*Jluulu*0ldddl*0u*1rdd*0r*7uldl*0d*3r*8urrdr*0d*4l*8u*1ruu*2lddrrrdrrr*7d*2lurrrururr*7ulllu*4l*1uluu*Ar*3d*9l*1uluurruu*Brdd*Blu*5l*Bd*2rurrrdrrdd*4r*8u*7l*1uluuruu*2ruuu*5ldd*0rd*8ru*6rddlu*2lddluullu*4ru*Fldd*Brddd*5rurrr*Iul*2d*2lddd*1r*2drr*4u*3ld*1l*0ulu*9r*6dll*2u*4lull*0ulluu*9ldd*7r*2d*0r*1urrululllu*9ldd*7r*0d*0r*0ulurrullu*Alddd*7r*Fd*4l*2u*0l*2druurdrd*0ruuu*4lu*1l*0u*2rd*0ldd*1r*0d*9rulul*Durrruuul*Jul*7dld*5r*0u*Gldd*Br*0d*1ru*3r*4dll*2u*6l*1ulu*9r*7dll*4d*7lurrulllu*7rddd*8lurrulllu*9rddd*Alurrulllu*8rddd*9lurrulllu*9rddd*Alurrulllu*8rddd*9lurrulllu*7rddd*8lurrulllu*8rddd*9luurrullu*2rdddrd*3luluulurru*0l*6u*0l*1drruuu)| +|[The Birdcage](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&32?*30101*901*12005*7010222*0122*002000104*20101*401100010011*701010201*40220020001*B01200021011002*A011*001*002011122*001*302011*1010002022202*A011101*2010500020001*401010101*0010001120001*601000101*10201222*201*301000101010002*F010001010*01221*401*4010100010022202*E010101*F01*30101010110*0200020110001*401010101*4020*11011*301110111*60*41*301110*H1/b0?442/s1?59/s0?30/b1?535&534&533&532&531&530&529&528&431/f5?361/b2?503&403/f7?463/f1?102/f2?174/f3?247/f4?343/f0?94/f6?415/f8?475/)|[Gooby](https://github.com/jmdiamond3)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&32?*30101*901*12005*7010222*0122*002000104*20101*401100010011*701010201*40220020001*B01200021011002*A011*001*002011122*001*302011*1010002022202*A011101*2010500020001*401010101*0010001120001*601000101*10201222*201*301000101010002*F010001010*01221*401*4010100010022202*E010101*F01*30101010110*0200020110001*401010101*4020*11011*301110111*60*41*301110*H1/b0?442/s1?59/s0?30/b1?535&534&533&532&531&530&529&528&431/f5?361/b2?503&403/f7?463/f1?102/f2?174/f3?247/f4?343/f0?94/f6?415/f8?475/#replay=nmGTi8PB&1rldrrul0ll1l0l1u0l1lul0l1lururrr0rrrll1rururuuluuruuluuruulldddllulullulu*2rdll0rr1uurr0rr1*0ur0r1ul0l1uul0l1urr0rr1ul0l1uu0r1lurruuru0r1uuullddldldll0rrru1dlll0*0ldlu1*4l*0uruuu*0luul*0u*8rdrrrddluuulldlldr*0dlddrrddl0ru*2luulurdd*1rurdl1dld0*1luulu1*1luul0u1*0u0ulluuu1ruulullluulll*0urrulluuu0llullu1uur0rrdrruuu1ruuu*0lddd*3rddlluulll*1drruull*2ur0lluluruullu1rull0uu1uu0l1uullu0lu*3rdll1uu*0ruuu*0lddd*0r0uul1r0uuluuu*6l1ruuu*6l)| +|[The Birds Uncaged](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&17&30?4*00101*901222*005*5010222*0122*00200012*10101*50100010011*501012201*40220020001*901200021011002*8011*001*002011122*001*1020112*0010002022202*8011101*001010500020001*201000101*401120001*401000101*10201222*201*101000101010002*D0100010100111221*401*20101000100222*E010101011*C01*10101010110*02*10110001*2010101011*20222*11011*101110*H1/s1?55/b0?414/s0?28/f0?94/f6?162/f2?231/f1?337/f8?433/f5?321/f4?88/f3?389/f7?445/)|[Joel Fox](https://joelthefox.github.io/)|Derived from Gooby's level above|☑| +|[Stripped](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&41?*701*101*F01005*Z01*801*101*C0211*B01*101*H01*n01*O01*F0101*60222*J011101*605*201*G0101*60112001*K0101*C01*F010101*W010101*B01*G0101*Y01*G01*F010110*02002220110001*G01011*60*110114*E0111*70*4101*B010*I1/b0?688&687&686&685&684&683&682&681&680&556/b1?568/b2?647/s3?39/s2?77/f8?673/f6?597/f2?132/f0?21/f1?441/f3?121/f5?532/f7?610/f4?320/)|[Gooby](https://github.com/jmdiamond3)|Based on The Birdcage and The Birds Uncaged|[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&41?*701*101*F01005*Z01*801*101*C0211*B01*101*H01*n01*O01*F0101*60222*J011101*605*201*G0101*60112001*K0101*C01*F010101*W010101*B01*G0101*Y01*G01*F010110*02002220110001*G01011*60*110114*E0111*70*4101*B010*I1/b0?688&687&686&685&684&683&682&681&680&556/b1?568/b2?647/s3?39/s2?77/f8?673/f6?597/f2?132/f0?21/f1?441/f3?121/f5?532/f7?610/f4?320/#replay=nmGTi8PB&2rldrrul3ll2l3l2u3l2lul3l2lururrr3rrrll2rururuuluuruuluuruulldd*3ldd*3rdll3r2ulll3lll2uul3ll2ll3lld2luuld3lu2*1lul*0uruuull*1ulll*0u*5lddd*5ru*0r*2drddd*1r3l2uu*1l3*2lu2l*2u3*0l2ruuulll*0dlll*3dr*3urruuu3urrul2ull3l2uu3ull2rrrdd*5lulluuurrd*0r3ll2urrr3*0l2*0dldllulu*8l3*5l2llld3l)| +|[Serpentine](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&20&39?112112*012*312*0121121211200*221112*21211211212*312*010002*612*312*2121112*3022141*O0111*002101*N0112110022101*O011120002101*Q0120022101*Q0120002101*Q0122022101*Q0120002101*Q0122022101*Q0120002101*Q0122022101*Q0120202101*Q01*12101*3022*B02*10*3101*4022*A022*801*40222*80*02*7011*20*12*70*12*601*Y21/b0?626&665&704&666&705&707&668&708&669&630&631&706&277&317&357&356&355&316/b2?318/s2?117&156&195&234&273&312&351&390&429&468&507&546&585&624&663/s3?629&628&627/)|[Gooby](https://github.com/jmdiamond3) & [Joel Fox](https://joelthefox.github.io/)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&20&39?112112*012*312*0121121211200*221112*21211211212*312*010002*612*312*2121112*3022141*O0111*002101*N0112110022101*O011120002101*Q0120022101*Q0120002101*Q0122022101*Q0120002101*Q0122022101*Q0120002101*Q0122022101*Q0120202101*Q01*12101*3022*B02*10*3101*4022*A022*801*40222*80*02*7011*20*12*70*12*601*Y21/b0?626&665&704&666&705&707&668&708&669&630&631&706&277&317&357&356&355&316/b2?318/s2?117&156&195&234&273&312&351&390&429&468&507&546&585&624&663/s3?629&628&627/#replay=nmGTi8PB&2*1r3ullulldluu2rrddl*3dlllurr*0uruuull*0urddrr*0dldlu*1l*0urdrurdruuu3r2rrru*1l*2ull*3dr*3urrruulu*3rdd*4l*2dl3ul2l*2u3u*2r2*Hr3*4r2*2u3*2r2uul*0u*2ru*0rdrdddr*2ulddlu*0ldl*3d*0l3r2uu3r2rrr*4urru*0rdrdddr*2ulddlu*0ldl*1dllluu3rr2rdru3r2uurruuld*0l3urr2*1lu*3r3ul2rd3uul2rrrdddlddd*1r3u*0rddld*1rdrulu*1l2rrru*0l3ulurur2ll*1u3u*3l2llu*6lu*6r*1drd*0rur3lu*0r2ru*3l*3u*6lu*5r*1drd*2rur3u*0rdlurd*2rurruu2*Bu)| +|[The Sawmill](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&30&32?*F02*202*R02*R02*301*C20022202*E01*802*5011*301002*A02*901*E02*80100220222*3021*A01*D051*801000*11011*301*801000*11*601*801000*61*101*8010*51001222001*801000*31051220001*801000*210001120001*801*A020001*80*610*51*T02022*60*0200220020002*D02*002002020002*D0*020*02020202*A04*10202002022022*D0*0202002020002*j02000202020002*F02202202020002*F02020202020002*F02000202020002*B01000200020202220222*U0/b3?115&147&179&211/b4?207&208&176/b0?78/b2?379&347&315&283/s2?508&509&510&478&446/s1?44/s0?46&45&77&76/f1?6/b1?255&220&188&156&124&92&60&28/f3?534/f2?341/f7?116/f4?221/)|[Gooby](https://github.com/jmdiamond3)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&30&32?*F02*202*R02*R02*301*C20022202*E01*802*5011*301002*A02*901*E02*80100220222*3021*A01*D051*801000*11011*301*801000*11*601*801000*61*101*8010*51001222001*801000*31051220001*801000*210001120001*801*A020001*80*610*51*T02022*60*020020020002*E02*00202020002*E0*020222020202*B04*1020202022022*E0*020202020002*k02000202020002*F02202202020002*F02020202020002*F02000202020002*B01000200020202220222*U0/b3?115&147&179&211/b4?207&208&176/b0?78/b2?379&347&315&283/s2?508&509&510&478&446/s1?44/s0?46&45&77&76/f1?6/b1?255&220&188&156&124&92&60&28/f3?534/f2?341/f7?116/f4?221/#replay=nmGTi8PB&1*5rl0rdddrr2urruuul0rrruuu2ddru0ruluruuuluuul2ulldrr0llurrrddrddldl2u0*5l*0urruuu*4rululul1d*0rdllluurru*6ldd*7ruldll0d*5l*0d*6ruruuulullulurrrddrddldl2lldrru0d1u0*5l*0urruuu*6rddlll1*7lur2l*0uruuluruuldd*5l1ulu2lu1urruu2uuuruuu*6ru0luu*3luur2*3lu0rrururuurrurrr*1dllluu2uururuurrrurrdddl0*4ldddr1l0uu1lu0uu1r2*2lu1rrrururu2u*0l*0d0uluu*8ruu2ruul*0urruuu*2rddrrruul0*0lurrr2uruu0uu*5lul1uru*2l2*3luuururuurulllu1urrurrd2l1*1lulll2llul0ul1lll0ddl1l0dd*2r1lllull2dluu*2ru*0l1luu0*0r2ldd*0r*0dlll1rdd*7rul2ur0*2ur)| +|[The Hardmill](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&24&32?*F02*202*R02*R02*301*C20022202*E01*802*601*301002*A02*901*E02*001*30100220222*3021*A01*D051*801000*11011*301*801000*11*601*801000*61*101*8010*51001222001*801000*31051220001*801000*210001120001*801*A020001*80*610*51*T02022*4020020020022200222*B0200202020200202002004*70*0202220222002002*A0200202020202002002*A020020202020020222*U0/b3?115&147&179&211/b4?207&208&176/b0?78/b2?379&347&315&283/s2?508&509&510&478&446/s1?44/s0?46&45&77&76/f1?6/f3?534/f2?341/f7?116/f4?221/b1?255&220&188&156&124&92&60&28/)|[Joel Fox](https://joelthefox.github.io/)|Derived from Gooby's level above|☑| +|[Mine Rescue](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&33&55?*o04*N02*41011*00*21*101*M0211*241011000*11010001110*21*E02111444*01011000100010112014102*012*D02*014441*00110001010101110141002112*D02*510*11000101*3014100022*D021141*30144410001012201000141*H02*110*314441*60*0141*G021100110*51411001100010001441*F0211*2011*2014410011*301441*E02111*20110*01014410111*00*01441*D0211*701441011410111*001*141*C02110001*202014410011101*20*01441*B02111*602014410001101*501441*A021141*60201441*20*11001001441*90211441*6020144*21*00111*001441*90114441*3010020144*21*001100*31*901*041*602014110001100011*4011*602101*041010*420111*101002100102010011*5021001*041*801*002001002101*3011*40211011*04*A10*71*002201011*302*00*014441*00*41*701*5011*20510*010011441021001*00*01*9012022111*2011*40*01*4010*0101*30100111011141*10*0101200101*3012001011*701001410144410002*1101*1010120221100010100110010001011011101444100211100051000111*3010101000111*70110014441*00110*0100*01011*201000111*60110100014441011*50*010011*001110*0100102*10211010001444*310111*4011*20101441001020020221101000144411*0410*810010100101441001022020221101010144411*041*B01*0010144*012220*0211010101444*H12*210*D10*51/b1?1275/b2?1617&1616&1560&1505&1450&1449&1448/b6?1357/b7?1302&1247/b8?1361&1306&1251/b9?1192&1193/b10?1527/b11?1245&1190/b12?1579&1524&1469&1414/b13?1359&1304/b14?1521/b16?764&763&762/b0?1279&1224/b15?1201&1202&1203&1147&1196/b21?627&572&517&518&463/b18?267/b19?212/b20?157/b4?1339/b3?1176/s0?114&115&116/s3?113&112&111/s1?1473/s2?1478&1533&1532&1587&1588&1643&1642&1697&1752/f1?91/f10?1682/f2?1518/f5?1519/f9?1026/f0?1177/f3?831/f6?886/f7?809/b22?810&424&369&370&371/f4?868/b5?321&322&323&46&47&48&49/)|[Gooby](https://github.com/jmdiamond3)|Allow time for solution to load|[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&33&55?*o04*N02*41011*00*21*101*M0211*241011000*11010001110*21*E02111444*01011000100010112014102*012*D02*014441*00110001010101110141002112*D02*510*11000101*3014100022*D021141*30144410001011101100141*H02*110*314441*60*0141*G021100110*51411001100010001441*F0211*2011*2014410011*301441*E02111*20110*01014410111*00*01441*D0211*701441011410111*001*141*C02110001*202014410011101*20*01441*B02111*602014410001101*501441*A021141*60201441*20*11001001441*90211441*6020144*21*00111*001441*90114441*3010020144*21*001100*31*901*041*602014110001100011*4011*602101*041010*420111*101002100102010011*5021001*041*801*002001002101*3011*40211011*04*A10*71*002201011*302*00*014441*00*41*701*5011*20510*010011441021001*00*01*9012022111*2011*40*01*4010*0101*30100111011141*10*0101200101*3012001011*701001410144410002*1101*1010120221100010100110010001011011101444100211100051000111*3010101000111*70110014441*00110*0100*01011*201000111*60110100014441011*50*010011*001110*0100102*10211010001444*310111*4011*20101441001020020221101000144411*0410*810010100101441001022020221101010144411*041*B01*0010144*012220*0211010101444*H12*210*D10*51/b1?1275/b2?1617&1616&1560&1505&1450&1449&1448/b6?1357/b7?1302&1247/b8?1361&1306&1251/b9?1192&1193/b10?1527/b11?1245&1190/b12?1579&1524&1469&1414/b13?1359&1304/b14?1521/b16?764&763&762/b0?1279&1224/b15?1201&1202&1203&1147&1196/b21?627&572&517&518&463/b18?267/b19?212/b20?157/b4?1339/b3?1176/s0?114&115&116/s3?113&112&111/s1?1473/s2?1478&1533&1532&1587&1588&1643&1642&1697&1752/f1?91/f10?1682/f2?1518/f5?1519/f9?1026/f0?1177/f3?831/f6?886/b5?322&323&46&47&48&49/f7?809/b22?810&424&369&370&371/f4?868/#replay=nmGTi8PB&3rru*3rddlddlllddrr0*2luurrrd*4ruurururruullurrddll3rrdruruldlulllddllur0ululllddlur3uruu0*0ur3ldlururul0rrdrdlldddld*2rur*0u*2rulld*0lddrrrddrdldd*Aluuu*1rd*1rur*0u*2rurrrddlddl3lldd*9rururrddrru0lllu*0ruuruullulullldddrrru*0rurr*1dlluuu3uluurruuruururrddrruru*1r0luuurrr*0drrururrrddrrru3uurrdll0urrddrruuulldlldlluulluururdrruurrddrrd3l0lldlldldlluuuluu*1rddld*0ruululll3ldrr1*4l3uruuluuru*0lulluurrruurrddrululldllldd*8ruu1llddluuruuu*0r0dd*3ruulu3u0u3rurururrruulllu*1ldrrurrruuurrrul0uurruruuluruululluurrruuuruu*1l*0urrdd*2ruuull3luulldddlldrrulldllurrdrrdrdrrruulllullurrdrrddllddlldldd1u*4ruuluullulldd*1ruuluu3rruruulururruullu*1ldrrurrruuuruullddlldrrulldllurrdrrdrdrrruulllullurrdrrddlldldldldd1llulldd*1ruuluu3rruruulururruullu*1ldrrurrruuuruu*0ldrrulldllurrdrrdrdrrruulllullurrdrrddlldldldldd1llulldd*1ruuluu3rruruulururruullu*1ldrrurrruuurrrul2r*3ulluluruulldlddrruruulldlddd1*0lur2dll*0drrruulu1ruurruuu2u1rurruurruullulu2*0ururur*0u1ruuruu2lll*1ullluuldl*0ururu1*3lddldddruuluuu3luu*3lddldddrrrdllululllululdd*1rdrrrdldl1rulu*1luru3ddl*1u*0l1luu3lu1u*1lddd*7luur3*0u*1l*1d*5luuulu*0ru1r3rr1uurrulll3u*1l*1u*0rdd*0l1l3lur*1urrruulll*1d1uu3llu1rruuulld3u*1r1*1r3r1uuldd*0ldddrruulu3r1uu*1ruuururuu3ul*0ururu1u*2ruurrruu3*0u*2ruur1u2ru*8r0u*0rur1u*Er3rr*0u*Er)| +|[Fruit Temple](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&38&55?*I01*901*c0*71*b01004*504001*a0*210*21*Z01004*00101*004001*Y0*1101010*11*X0100400010101010004001*W0*01010101010*01*V010040010101010101004001*U01110101010101010111*T01004*D04001*S0110101010101010101011*R01004*F04001*Q0111010101010*11010111*P01004*901*304001*O0*21010101010101010*01*N01004*J04001*M0*11010101010101010*31*L01004*B01*504001*K0*2101010101011101010*21*J01004*601*C04001*I0*510101110101110*51*H01004*901*B04001*G0*4101010101010101010*41*F01004*R04001*E0*51010101010111010*71*D01004*301*101*101*904001*C0*410101011101010111010*61*B01004*201*301*501*604001*A0*31011101010101010101010*71*901004*101*R04001*80*210*1101010101010101010*81*701004*001*101*701*101*604001*60*110*11011101110101011101110*71*5010040001*101*1010001010001*101*504001*40*010*110*31010101010*310*61*901*101*501010101*501*80*510*110*7101010*710*71/s2?1983&1928&1873&1818&1763&1708&1653&1598&1543&1488&1433&1378&1323&1268&1213&1158&1103&1048&993&938&883&828&773&718&663&608&553&498&443&388&333&278&223&168&113&58&3&2&57&112&167&222&277&332&387&442&497&552&607&662&717&772&827&882&937&992&1047&1102&1157&1212&1267&1322&1377&1432&1487&1542&1597&1652&1707&1762&1817&1872&1927&1982&1981&1926&1871&1816&1761&1706&1651&1596&1541&1486&1431&1376&1321&1266&1211&1156&1101&1046&991&936&881&826&771&716&661&606&551&496&441&386&331&276&221&166&111&56&1&0&55&110&165&220&275&330&385&440&495&550&605&660&715&770&825&880&935&990&1045&1100&1155&1210&1265&1320&1375&1430&1485&1540&1595&1650&1705&1760&1815&1870&1925&1980/b0?132&133/b1?146&145/b2?241&242/b3?257&256/b4?350&351/b5?368&367/b6?459&460/b7?479&478/b8?569&568/f0?571/f1?573/f2?575/f3?577/f4?579/f5?581/f6?583/f7?585/f8?587/b9?590&589/b10?678&677/f9?681/f10?683/f11?685/f12?687/f13?689/f14?691/f15?693/f16?695/f17?697/b11?701&700/b12?786&787/f18?791/f19?793/f20?795/f21?797/f22?799/f23?801/f24?803/f25?805/f26?807/b13?812&811/b14?895&896/f27?901/f28?903/f29?905/f30?907/f31?909/f32?911/f33?913/f34?915/f35?917/b15?923&922/b16?1004&1005/f36?1011/f37?1013/f38?1015/f39?1017/f40?1019/f41?1021/f42?1023/f43?1025/f44?1027/b17?1034&1033/b18?1114&1113/f45?1121/f46?1123/f47?1125/f48?1127/f49?1129/f50?1131/f51?1133/f52?1135/f53?1137/b19?1145&1144/b20?1222&1223/f54?1231/f55?1233/f56?1235/f57?1237/f58?1239/f59?1241/f60?1243/f61?1245/f62?1247/b21?1256&1255/b22?1332&1331/f63?1341/f64?1343/f65?1345/f66?1347/f67?1349/f68?1351/f69?1353/f70?1355/f71?1357/b23?1367&1366/f72?1451/f73?1453/f74?1455/f75?1457/f76?1459/f77?1461/f78?1463/f79?1465/f80?1467/b24?1478&1477/f81?1561/f82?1563/f83?1565/f84?1567/f85?1569/f86?1571/f87?1573/f88?1575/f89?1577/b25?1589&1588/f90?1671/f91?1673/f92?1675/f93?1677/f94?1679/f95?1681/f96?1683/f97?1685/f98?1687/b26?1699&1700/f99?1781/f100?1783/f101?1785/f102?1787/f103?1789/f104?1791/f105?1793/f106?1795/f107?1797/b27?1810&1811/b28?1921&1922/b29?1441&1440/b30?1550&1549/b31?1659&1658/b32?1768&1767/b33?1877&1876/)|[XeroOl](https://github.com/XeroOl)|I'm sorry|| +|[Plane Crash](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&55?*q0*n4004*72*a04004*702*Z04004*802*Y04004*90*02*U04004*D02*T04004*E02*S04004*F0*32*L04004*M02*K04004*N02*J04004*O0*62*904004*Y02*804004*Z02*704004*a0222*404004*d02*304004*e02*20400400*040*04*004000*04040004*C0*02004004004*004004000404004*0040004*G0204004004*004004004000404*0040004*I04004004*00*0400400040*040*14*I04004004*00404000*14*004040004*I04004004*0040040040004*004040004*I0400400*040400040400040*04040004*I04004*l0400*n4*q0/b0?61&226&281&336&391&446&501&556&611&666&390&389&388&387&331&441&386&392&338&339&340&395&450&449&448&393/s3?394/)|[Gooby](https://github.com/jmdiamond3)|Novelty Guess-the-Exit Special|[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&55?*q0*n4004*72*a04004*702*Z04004*802*Y04004*90*02*U04004*D02*T04004*E02*S04004*F0*32*L04004*M02*K04004*N02*J04004*O0*62*904004*Y02*804004*Z02*704004*a0222*404004*d02*304004*e02*20400400*040*04*004000*04040004*C0*02004004004*004004000404004*0040004*G0204004004*004004004000404*0040004*I04004004*00*0400400040*040*14*I04004004*00404000*14*004040004*I04004004*0040040040004*004040004*I0400400*040400040400040*04040004*I04004*l0400*n4*q0/b0?61&226&281&336&391&446&501&556&611&666&390&389&388&387&331&441&386&392&338&339&340&395&450&449&448&393/s3?394/#replay=nmGTi8PB&3*br)| +|[Top Shelf](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&28?*z0*V01*N01*G0*41*B0111*z0*z0*z0*z0*604*z0*z0*z0*z0*K0*1100*51*60/b1?95&123&124&96/b2?97&125&126&98/b4?146&145&144&649/s2?706&705&704&703&702/b3?99&127&659/b0?93&94&122&121/)|[Gooby](https://github.com/jmdiamond3)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&28?*z0*V01*N01*G0*41*B0111*z0*z0*z0*z0*604*z0*z0*z0*z0*K0*1100*51*60/b1?95&123&124&96/b2?97&125&126&98/b4?146&145&144&649/s2?706&705&704&703&702/b3?99&127&659/b0?93&94&122&121/#replay=nmGTi8PB&2uuulld*8ruulld*1luullluru*1rurrdlluulluuuluuulll*0druurulluruluuulldrdrruururrdllullldddrruuru*0ldd*1rulullullldrruuurrrddrdlluullurrrdruurulluruurulu*2rdddllluululurruru*5lddruu*0rddldlullurrulllurrrdrurullurrulurruurrururrrddd*0luululurullurrruurullurrulurru*2ld*0ruuurdruulurul*0ur*0urulurrulllddruuurru*1ld*0ruur*0urullurrulurruu*3r)| +|[Top Shelf 2](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&28?*z0*z0*o01*N01*G0*41*B0111*z0*z0*z0*z0*604*z0*z0*z0*10*1100*51*60/b0?180&208&209&181/b1?183&211&659/b2?207&206&205/b3?210/b4?230&229&228&649/s2?706&705&704&703&702/)|[Gooby](https://github.com/jmdiamond3)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&30&28?*z0*z0*o01*N01*G0*41*B0111*z0*z0*z0*z0*z0*P04*z0*z0*z0*10*1100*51*60/b0?180&208&209&181/b1?183&211&743/b2?207&206&205/b3?210/b4?230&229&228&733/s2?790&789&788&787&786/#replay=nmGTi8PB&2uuulld*8ruullluulluuulldlllururrurrrdlluuu*0ldddrdrurrullurululurrddllluurul*0ullldddrruu*0rddldlullurrurrurrdllullldddrdrurrulluruluulldluurulu*0rdddldlullurruurullddrdrurru*1luruuluulull*0druuluruuruulldddrrruuulurullldrruuu*1rdddldlullurruluruluuullldrrruuurulllddrrruuurulu*0ldrruurulurrullddrrdrurrullurululullldddruuluruu*2rdllldlulluuurrrdrddldlullurrulururullddrrrulurruuldddrrulur*0u*0rdddluulullurrru*0ldddruurullddrrrulurrururullurrddlulllddrruluurulu*0rddllurulluuru*1ldrruuurulurullddrruulur*0urulurruurrulluullddruulurullddrruuruulurruulurrulllddrruluruuur*0urrdll*0ullururrdllldrruuurulllddruurur*0u*3r)| +|[Plinko](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&23&29?*u011*N01*O0110*91*A0101*M0101*M01011*001*G01041*401*C01011*L01010001*I0101*A01*70101*M0101*501*C010102*K01012001*I0101*C01*5010102*K0101*301*E01*O01*O0101*M010102*H0/b12?180&181&182&183&184&213/b0?93/b1?94/b2?95/b3?96/b4?97/b5?98/b6?99/b7?100/b8?101/b9?102/b10?103/b11?104/s1?70&71&72&73&74&75/s0?90/s2?69&68&67&66&65&64/)|[Gooby](https://github.com/jmdiamond3)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&23&29?*u011*N01*O0110*91*A0101*M0101*M01011*001*G01041*401*C01011*L01010001*I0101*A01*70101*M0101*501*C010102*K01012001*I0101*C01*5010102*K0101*301*E01*O01*O0101*M010102*H0/s0?90/b12?180&181&182&183&184&213/s2?69&68&67&66&65&64/s1?70&71&72&73&74&75/b0?93/b1?94/b2?95/b3?96/b4?97/b5?98/b6?99/b7?100/b8?101/b9?102/b10?103/b11?104/#replay=nmGTi8PB&2*2ru*9ldrrru*9rdddl1*1l2lllurrrd*0l1lll2lll1l2dl1u2l1ur2uuurul*1ulldddrrr1rr2ruuur1ullururddd*2l2ulll*1ulldddrrrdlllu*0ruur1ururrruurr*0ull2uluuull*1uluu*6rdrruuu*0lu*0rd*8l1luurr*1ullld*0rullldddrdrrrurrurr2uurrurru*5r*0d*1l1rrrurrddllluldluurulurrrdllld*1l2*3lulurrruuu1u2r1lulurr*0dld*0l2rrullldd*1l1uu*2ruuuruu*0luuuru*2rdd*1ld*0rddllulllurrrddrddllulllurrrd*0l2ulur1*1urul2rrulll1u*2rddlllurrrddll2uu*0r1lul2r1*0u2u1lll2urr*0u*0lullldrrrurrr*0dlluuurrull*1u1uuurul*1ul2*0rddlllull1ldddrdl*0drurrrurrdd*0lurrur2urrurruruulll1*0ullluu*1r2uuurruuullldrrrullldd*2ru*3r1uulu*2rur2ulll1rrd*0l2uuur1lu2u1uu2urulurru*3lu*1rurrulluuul1r*1uluuu*Bl2*9l*1dr0rr1l*1dr)| +|[The Puppet Master](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&21&41?*002*F02*G02*U04*102*F02*G02*501*502*H0*F1*D05*q05*801*z0*z0*002221*I01*z0*B01*z0*z0*z0*z0*h0*F1*D0/b1?146&719&593&473&311&273&285/b0?128&744&629&507&345&189&248&577/b2?372&331&290/s1?752&793&794/s3?55&96/f0?537/)|[Gooby](https://github.com/jmdiamond3)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&21&41?*002*F02*G02*U04*102*F02*G02*501*502*H0*F1*D05*q05*801*z0*z0*002221*I01*z0*B01*z0*z0*z0*z0*h0*F1*D0/b1?146&719&593&473&311&273&285/b0?128&744&629&507&345&189&248&577/b2?372&331&290/s1?752&793&794/s3?55&96/f0?537/#replay=nmGTi8PB&1*5ruu*Elurdrruul3*3lulld*2ru*6rurrd*2l1urr3u*0ld*1l1uur3u*1rurrdrr1ul3r1u3r1ruurrurrr3rr1rr3u*2lu*3lulld*2r1rruuruuluu*2r3u*5rurrd*2l1rrr3ulldrr1ul3urrdl1ll3l1*0l3ulld*2r1*0lurr3urrd*2lu*0ld*3lu*3ru*0rdl1rrddllu*7ruuruuuruulldrrruuullu3ul1uruul3ldrr1urururuuururrr3urrdll1rullddr*0u3u*7lu1rrulldrrdddld*0ruuurrddllluruuul3*3rurrd*3rur1u*Bruu3*0ru*0l1ru*Dluuulld*9ruuurrrdd3*0l1luurulu*0rulll3urul1luuu3ll1*Alurrrurrd*2ruurr3ururrr1uurruuuru3ul1lul3ll1ulur3urr1ur3r1uruu3r1urur3rr1rr3rr1u*0r3rrr1uuru3rrrurr1luu*2r3*0r1uluru3uldruruu1uuu)| +|[Rainbow Bridge](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&14&40?*z0*z0*N04*z0*F0*N1*z0*z0*z0*10*21*z0*G0/b2?206/b8?212/b9?213/b10?214/b3?207/b13?217/b18?222/b14?218/b19?223/b6?210/b5?209/b4?208/b23?227/b12?216/b17?221/b24?228/b20?224/b0?204/s0?203&202/b7?211/b15?219/b1?205/b11?215/b16?220/b21?225/b22?226/f1?109/)|[Gooby](https://github.com/jmdiamond3)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&14&40?*z0*z0*N04*z0*F0*N1*z0*z0*z0*10*21*z0*G0/b2?206/b8?212/b9?213/b10?214/b3?207/b13?217/b18?222/b14?218/b19?223/b6?210/b5?209/b4?208/b23?227/b12?216/b17?221/b24?228/b20?224/b0?204/s0?203&202/b7?211/b15?219/b1?205/b11?215/b16?220/b21?225/b22?226/f1?109/#replay=nmGTi8PB&*Krurruu*1rdluululluuluruluruurulurulddlldruldruldruruluruuruluruurulurullldruruluruuruluruuruluruu*0r)| +|[Castle](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&25&43?*z0*v04*z0*z0*H0101*Y02110112*G0101010101*3011000110001010101010101*00*51*2011*101100*91*00*51*1011*30110*91*00*21*30110021012001000*71*00*01*401100011011*20*71*00*31*00110001110111*00*81*00*31*40*010*0100*91*00*310011000*110*11000*71*00*310112*60*11002*61*00*51000*3100*21000*51*00*41000*01001101100*01000*41*00*31000*11001101100*11000*31*00*21000*21*50*21000*21*00*1100011*F011000*11*00*01000*810*81000*01*00111*T0111*00*Z100/b0?237/s0?238&281/s1?234&277/b1?524&525&526&527&528/f0?791/f1?798/)|[Gooby](https://github.com/jmdiamond3)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&25&43?*z0*v04*z0*z0*H0101*Y02110112*G0101010101*3011000110001010101010101*00*51*2011*101100*91*00*51*1011*30110*91*00*21*30110021012001000*71*00*01*401100011011*20*71*00*31*00110001110111*00*81*00*31*40*010*0100*91*00*310011000*110*11000*71*00*310112*60*11002*61*00*51000*3100*21000*51*00*41000*01001101100*01000*41*00*31000*11001101100*11000*31*00*21000*21*50*21000*21*00*1100011*F011000*11*00*01000*810*81000*01*00111*T0111*00*Z100/b0?237/s0?238&281/s1?234&277/b1?524&525&526&527&528/f0?791/f1?798/#replay=nmGTi8PB&1rrd0lldldrrruruurd*2luluuldd*0r1*Alu0dd*9l1rurururururu*4r0llurrd*9ru1urrdl0uurr1ll0uuuru*3lullddldldldldldd*8r1urd*Aru0*Ar1lululululululululur0uulululululululu1rul0urul1u0u1lul0urullluluu*2lddldld*0luurururururuurru*3rdrddlulu1llull0rruuulluluu*2lddldldldd*3rdld1d*2l0dd*9luururururur1l0uurullullurrdrdddld1ulululllur0ldldldlddluurrururururuuullulld1ur0druuluruururruulurrdldlldlddluur1u0r1l0urur1ur0ur1ur0ur1ur0ur1ur0ur1ururrr0uuurrr1urrru*0lulldrr0ur1ur0rr1rr0rr1rr0rddru1drru0r1r0rr1rr0rr1rr0rr1rr0rr1rr0rr1rr0rr1*0r0ur*0u)| +|[Perch](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&20?*O02*V01001*504*Q02*B010002*F021*A010002*F02*B010002*F02*B010002*F02*B010002*F02*B010002*F0222*901*Y0100222*F02*F02*F02*F021*N02*00*312*0021*00/b0?88&89&90/s3?110&109&129&130&131&111/f0?376/)|[Gooby](https://github.com/jmdiamond3)||[☑](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&25&20?*K01001*504*Q02*B010002*F021*A010002*F02*B010002*F02*B010002*F02*B010002*F02*B010002*F02*B01*Y0100202*F02*A01*002*F02*F021*N02*00*41*101*00/b0?48&49&50/s3?70&69&89&90&91&71/f0?336/#replay=nmGTi8PB&3uruulllullddllluuu*1rdrurrddlluruluruuluuluu*1l*1d*0ru*5ru*Blu*5ruuluuurrulluuurul*0ululllullddrdruuullddrr*0ullddrr*0ullddrr*0ullddrr*0ullddrr*0ullddrr*0ulurruullldd*0rulllurururrd*5r)| +--- -And check out some levels people have made: +# Experimental Snakebird Puzzles -[Snakefall Wiki](https://github.com/thejoshwolfe/snakefall/wiki) +[Experimental Template 1](https://jmdiamond3.github.io/Snakefall-Redesign/experimental/patashu-remix-1/#level=HyRr4JK1&19&35?*z0*z0*z0*z0*z0*z0*z0*z0*z0*z0*B0/) -## Bugs and Ideas - -See the [issue tracker](https://github.com/thejoshwolfe/snakefall/issues). - -## Version History - -#### 1.1.0 - -* Ability to share replays. ([issue #9](https://github.com/thejoshwolfe/snakefall/issues/9)) -* Redoing normal movement shows the animation just like if you were playing. -* Remove "playtest" button and overhaul dirty states. -* Use semver-like version numbers instead of just linking to the git hash. -* Finally add a link to the wiki on the actual game page. - -#### 1.0.0 - -* Game Engine: - * Everything from the original game (except that the left, right, and top border of the map are impassable). - * Undo and redo movement. Repeatedly hitting redo after a reset will effectively show a replay. - * Arbitrarily many snakes. A fourth snake color (yellow). More hotkeys for switching snakes. - * Size-1 snakes. -* Editor: - * Edit the game while it's running. - * Undo/redo edits independently of undo/redo normal movement. Can create time travel paradoxes. - * Resize the world. - * Select/Cut/Copy/Paste (but not between browser tabs). - * Cheatcodes to turn off gravity and collision detection (noclip) while editing. - * Share levels with a url that encodes the level. No server-side saving (because there's no server at all). +[Experimental Template 2](https://jmdiamond3.github.io/Snakefall-Redesign/experimental/patashu-puzzle-pack-1/#level=3tFRIoTU&23&34?*z0*z0*z0*z0*z0*z0*z0*z0*z0*z0*z0*z000/) +|Snakebird Level|Creator|Note|S/V| +|---|:---:|:---:|:---:| +|[Under Cover](https://jmdiamond3.github.io/Snakefall-Redesign/experimental/patashu-remix-1/#level=HyRr4JK1&11&14?001*80111*W02*5016161000*2600101*30201110140002001*101200210012120111001100*0121*001*001*20/s4?48&49&50&51&52/f1?81/f0?79/s3?34&35&36&37&38/)|[XeroOl](https://github.com/XeroOl)||☑| +|[Snake Filter](https://jmdiamond3.github.io/Snakefall-Redesign/experimental/patashu-remix-1/#level=HyRr4JK1&19&9?*L04*702112*A016612*001001001*101*0011001*2066*t0*11*00*11*00/b0?61&35/b1?83&74&75/s1?147&146&145&144/s2?138&137&136&135/)|[XeroOl](https://github.com/XeroOl)||☑| +|[Platformway to Heaven](https://jmdiamond3.github.io/Snakefall-Redesign/experimental/patashu-remix-1/#level=HyRr4JK1&18&16?04*l06*B06*F0*02*306*00*012*5060*11200066*40111*506022111*106*501*606*001*20101*201*10100*41*30*41*001*00*21*10*2100111*20*01*0011000/s0?114&113&129/b0?187&188&139/)|[thejoshwolfe](https://github.com/thejoshwolfe)||☑| +|[Under Cover 2](https://jmdiamond3.github.io/Snakefall-Redesign/experimental/patashu-remix-1/#level=HyRr4JK1&7&12?*j021*6042*16*402*30/s1?31&30&29&28&27/s2?15&16&17&18&19/s3?55&54&53&52&51/s0?39&40&41&42&43/f0?73/)|[XeroOl](https://github.com/XeroOl)||☑| +|[Low Clearance](https://jmdiamond3.github.io/Snakefall-Redesign/experimental/patashu-remix-1/#level=HyRr4JK1&15&31?*B01*Q01*Q01*Q01*Q01*D04*801*Q01*m0*F6*z0*z0*w0/b0?204&235&234&203/s0?196&195&194&193&192/s2?134&133&132&131&130/s1?165&164&163&162&161/s3?227&226&225&224&223/)|[XeroOl](https://github.com/XeroOl)||☑| +|[Baited Trap](https://jmdiamond3.github.io/Snakefall-Redesign/experimental/patashu-remix-1/#level=HyRr4JK1&16&13?*F04*J0*11*4010001*4010001*4010001*4016661*u0*11*d0/s0?134&135&136&137&138&151&150&149&148&147/f0?71/)|[XeroOl](https://github.com/XeroOl)||☑| +|[Gateway to Freedom](https://jmdiamond3.github.io/Snakefall-Redesign/experimental/patashu-puzzle-pack-1/#level=3tFRIoTU&17&20?*q03*N01*00*11oo*90*11*20*12*10*012*10*11*20*01*10*11*20*01*12*01*40*81*50*61*90*31*B01114*E011101221110o0o0011001110*21*2011001110*11*301100/s3?64&65/s5?73&72&71/b0?262&277/)|[LevelWorld](https://github.com/Fargogoosey)||☑| +|[House on Fire](https://jmdiamond3.github.io/Snakefall-Redesign/patashu-remix-1/#level=HyRr4JK1&35&49?*z0*o0*41*Z0*81*G0101*80*C1*E0101*60*G1*C0101*40*K1*A0101*20*O1*80101*00*S1*6010100*010*R1*4010*310*B1*00*A1*20101*H02*001100*02*801016*110*6100100020001002000*21*201016*9021120*0122*A01*20101600011002*01*601112*0026*201*201012*002000*110026*701226*201*201016001010101000110006*202*0022*301*201016002*6011226*5020226*201*201016*40211101*0021200012120226*002*40101602*40110101*0026*30226*306*10101602260211101*20200260222*00261*00116*101016000602002*30100026*4026*2016*101016222622000601001*5020001126*306*1010160006000206*501001020*126*2026*1010160001*106000*110022*002*006*306*101016*101002620010001*00620016*716*101016*3010600010401*40161*606*10101601*3061001000100221001161*40116*1010160001*5010001*00100016*6016*101016*101*3010051005000201*7016*1010160002*002*0010001*0010001*70162*001000*9210001202210001*502016*10*E1000*I161*z0*V0/b0?151&150&149/b1?795&746&697&648&599&550&452/b2?572&621&669&668&667&816/b3?578&676&725&823/b4?579/b5?580&678&727&776&874/b6?764&763&762&761&760&711&710&708&810&859&1105/b7?822/b8?842&844&850&1438/b9?848/b10?871/b11?920/b12?944/b13?969/b14?1215&1166&1068&1019&970/b15?1216&1167&1069&971/b16?1020/b18?1067&1116&1214/b20?1347&1151&1150/b21?1290/b22?1364&1363&1362/b23?1410/b24?1412/b25?1459/b26?1461/b27?1506&1555/b28?1557&1508/b29?1559&1510/b30?1511&1560/b34?1046/b17?1449&1448&1497/s3?1565/f6?1495/b19?1106/f8?1548/f5?1403/f3?1062/f0?567/f1?793/f2?876/f4?1318/f7?1524/)|[Gooby](https://github.com/jmdiamond3)||☑| +|[Underground](https://jmdiamond3.github.io/Snakefall-Redesign/experimental/patashu-puzzle-pack-1/#level=3tFRIoTU&23&33?0*Bt0*zt*zt*zt*zt*zt*Xt4*zt*zt*zt*zt*Wt3*it0*Tt/b0?16/s5?0/s6?725/)|[Gooby](https://github.com/jmdiamond3)||☑| From 249771ad84f181e35f2969956910777193d9e735 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 20:28:22 -0500 Subject: [PATCH 055/577] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 24a48245..ee6db83a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Josh Wolfe's Snakefall -This is a redesign of Josh Wolfe's [Snakefall](https://github.com/thejoshwolfe/snakefall), which is a level editor for the award-winning game [Snakebird](http://snakebird.noumenongames.com). +This is a redesign of Josh Wolfe's [Snakefall](https://github.com/thejoshwolfe/snakefall), which is a level editor for the award-winning game [Snakebird](http://snakebird.noumenongames.com). This redesign involves graphics upgrades only and uses Snakefall's original framework. # Standard Snakebird Puzzles From c24eb9b5ec0106ab5bc4cee2da076545bfcc12f3 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 23 Jan 2020 21:52:25 -0500 Subject: [PATCH 056/577] Update a.js --- a.js | 73 +++++++++++++++++++++++++++++++----------------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/a.js b/a.js index f930d5b4..59aa8123 100644 --- a/a.js +++ b/a.js @@ -1608,21 +1608,26 @@ function isAnyCheatcodeEnabled() { !isGravityEnabled || !isCollisionEnabled ); } -var bg2 = "rgba(230, 230, 255 * rgba(220, 220, 255"; var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; +var bg2 = "rgba(254, 198, 145 * rgba(255, 192, 133"; +var bg3 = "rgba(145, 254, 198 * rgba(117, 255, 192"; //var theme = "gradient"; var themeName = "Spring"; -var background; -var surface; -var material; +var background, surface, material, sc, ssc1, ssc2, bc; +var fruitColors1 = ["#ff0066","#ff36a6","#ff6b1f","#ff9900","#ff2600"]; +var fruitColors2 = ["black","black","black","black","black"]; var curlyOutline = false; + var themeCounter = 0; -var themes = [ //name, background, material, surface, curlyOutline + +var themes = [ //name, background, material, surface, curlyOutline, spikeColor, spikeSupportColor1, spikeSupportColor2, boltColor, fruitColors, stemColor //["sky",], - ["Spring", bg1, "#976537", "#95ff45", true], - ["Winter", bg1, "#30455B", "white", true], - ["Classic", bg1, "#844204", "#282", false], - ["Midnight Rainbow", "#070753", "black", "rainbow", false] + ["Spring", bg1, "#976537", "#95ff45", true, "#999", "#444", "#555", "#777", fruitColors1, "green"], + ["Winter", bg1, "#30455B", "white", true, "#999", "#444", "#555", "#777", fruitColors1, "green"], + ["Classic", bg1, "#844204", "#282", false, "#999", "#444", "#555", "#777", fruitColors1, "green"], + ["Summer", bg2, "#976537", "#95ff45", true, "#999", "#444", "#555", "#777", fruitColors1, "green"], + ["Dream", bg3, "#00aaff", "#ffb3ec", true, "#999", "#444", "#555", "#777", fruitColors2, "white"], + ["Midnight Rainbow", "#070753", "black", "rainbow", false, "black", "black", "black", "black", "white", "white"] ]; @@ -2076,8 +2081,6 @@ var rainbowBackground = ["white"]; /*var blockForeground = ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"]; var blockBackground = ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"];*/ -var fruitColors = ["#ff3399","#ff526b","#ff703d","#ff851f","#ff9900"]; - var activeSnakeId = null; var SLITHER_HEAD = "sh"; @@ -2146,6 +2149,10 @@ function render() { background = themes[themeCounter][1]; material = themes[themeCounter][2]; surface = themes[themeCounter][3]; + sc = themes[themeCounter][5]; + ssc1 = themes[themeCounter][6]; + ssc2 = themes[themeCounter][7]; + bc = themes[themeCounter][8]; curlyOutline = themes[themeCounter][4]; if(background.substr(0,1) == "#") { context.fillStyle = background; @@ -2154,8 +2161,8 @@ function render() { else{ for(var i = 0; i Date: Fri, 24 Jan 2020 02:42:19 -0500 Subject: [PATCH 057/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index ad4953fa..2f81f0f2 100644 --- a/index.html +++ b/index.html @@ -42,7 +42,7 @@ - + From d0587578d6e03ff22e764c0169dbfe61aaacf10f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 12:38:10 -0500 Subject: [PATCH 058/577] Update a.js --- a.js | 102 +++++++++++++++++++++++++++++++---------------------------- 1 file changed, 53 insertions(+), 49 deletions(-) diff --git a/a.js b/a.js index 59aa8123..d184771a 100644 --- a/a.js +++ b/a.js @@ -1608,26 +1608,46 @@ function isAnyCheatcodeEnabled() { !isGravityEnabled || !isCollisionEnabled ); } +var themeName = "Spring"; //themeCenter Gooby +var background, surface, material, blockColors, spikeColors, textStyle; +var curlyOutline = false; + var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; var bg2 = "rgba(254, 198, 145 * rgba(255, 192, 133"; var bg3 = "rgba(145, 254, 198 * rgba(117, 255, 192"; -//var theme = "gradient"; -var themeName = "Spring"; -var background, surface, material, sc, ssc1, ssc2, bc; + var fruitColors1 = ["#ff0066","#ff36a6","#ff6b1f","#ff9900","#ff2600"]; var fruitColors2 = ["black","black","black","black","black"]; -var curlyOutline = false; + +var spikeColors1 = ["#999", "#444", "#555", "#777"]; +var spikeColors2 = ["black", "black", "black", "black"]; + +var blockColors1 = [ + ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"], + ["#853641","#963c84","#753d88","#5d3a96","#3a3990"] +]; +var blockColors2 = [ + ["white"], + ["white"] +]; +var blockColors3 = [ + ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"], + ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] +]; + +var textStyle1 = ["150px Impact", "#fdc122", "#fd0c0b"]; +var textStyle2 = ["150px Impact", "#00aaff", "#ffb3ec"]; var themeCounter = 0; -var themes = [ //name, background, material, surface, curlyOutline, spikeColor, spikeSupportColor1, spikeSupportColor2, boltColor, fruitColors, stemColor +var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor //["sky",], - ["Spring", bg1, "#976537", "#95ff45", true, "#999", "#444", "#555", "#777", fruitColors1, "green"], - ["Winter", bg1, "#30455B", "white", true, "#999", "#444", "#555", "#777", fruitColors1, "green"], - ["Classic", bg1, "#844204", "#282", false, "#999", "#444", "#555", "#777", fruitColors1, "green"], - ["Summer", bg2, "#976537", "#95ff45", true, "#999", "#444", "#555", "#777", fruitColors1, "green"], - ["Dream", bg3, "#00aaff", "#ffb3ec", true, "#999", "#444", "#555", "#777", fruitColors2, "white"], - ["Midnight Rainbow", "#070753", "black", "rainbow", false, "black", "black", "black", "black", "white", "white"] + ["Spring", bg1, "#976537", "#95ff45", true, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], + ["Winter", bg1, "#30455B", "white", true, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], + ["Classic", bg1, "#844204", "#282", false, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], + ["Summer", bg2, "#976537", "#95ff45", true, blockColors3, spikeColors1, fruitColors1, "green", textStyle1], + ["Dream", bg3, "#00aaff", "#ffb3ec", true, blockColors1, spikeColors1, fruitColors2, "white", textStyle2], + ["Midnight Rainbow", "#070753", "black", "rainbow", false, blockColors2, spikeColors2, "white", "white", textStyle1] ]; @@ -2072,15 +2092,6 @@ var snakeAltColors = [ "#ffff66", ]; -var blockForeground = ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"]; -var blockBackground = ["#853641","#963c84","#753d88","#5d3a96","#3a3990"]; - -var rainbowForeground = ["white"]; -var rainbowBackground = ["white"]; - -/*var blockForeground = ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"]; -var blockBackground = ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"];*/ - var activeSnakeId = null; var SLITHER_HEAD = "sh"; @@ -2149,10 +2160,10 @@ function render() { background = themes[themeCounter][1]; material = themes[themeCounter][2]; surface = themes[themeCounter][3]; - sc = themes[themeCounter][5]; - ssc1 = themes[themeCounter][6]; - ssc2 = themes[themeCounter][7]; - bc = themes[themeCounter][8]; + blockColors = themes[themeCounter][5]; + spikeColors = themes[themeCounter][6]; + textStyle = themes[themeCounter][9]; + curlyOutline = themes[themeCounter][4]; if(background.substr(0,1) == "#") { context.fillStyle = background; @@ -2283,14 +2294,8 @@ function render() { rowcol2.r -= minR; rowcol2.c -= minC; var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; - if(surface == "rainbow"){ - drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, rainbowBackground[object.id % rainbowBackground.length]); - drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, rainbowBackground[object.id % rainbowBackground.length]); - } - else{ - drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockBackground[object.id % blockBackground.length]); - drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockBackground[object.id % blockBackground.length]); - } + drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); + drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); } } var r = minR + animationDisplacementRowcol.r; @@ -2314,8 +2319,8 @@ function render() { // banners if (countSnakes() === 0) { - context.fillStyle = "#fdc122"; - context.font = "150px Impact"; + context.fillStyle = textStyle[1]; + context.font = textStyle[0]; context.shadowOffsetX = 5; context.shadowOffsetY = 5; context.shadowColor = "rgba(0,0,0,0.5)"; @@ -2325,8 +2330,8 @@ function render() { context.fillText(textString, (canvas.width/2) - (textWidth/2), canvas.height/2); } if (isDead()) { - context.fillStyle = "#fd0c0b"; - context.font = "150px Impact"; + context.fillStyle = textStyle[2]; + context.font = textStyle[0]; context.shadowOffsetX = 5; context.shadowOffsetY = 5; context.shadowColor = "rgba(0,0,0,0.5)"; @@ -2515,7 +2520,7 @@ function render() { drawBlock(object); break; case FRUIT: //Gooby - var fc = themes[themeCounter][9]; + var fc = themes[themeCounter][7]; rowcol = getRowcol(level, object.locations[0]); var c = rowcol.c; var r = rowcol.r; @@ -2545,7 +2550,7 @@ function render() { context.moveTo(startC,startR); context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); - context.fillStyle = themes[themeCounter][10]; + context.fillStyle = themes[themeCounter][8]; context.fill(); } else drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); @@ -2793,7 +2798,7 @@ function render() { function drawSpikes(r, c, adjacentTiles) { var x = c * tileSize; var y = r * tileSize; - context.fillStyle = sc; + context.fillStyle = spikeColors[0]; context.beginPath(); context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes @@ -2854,14 +2859,14 @@ function render() { var boltBool = false; var occupiedCount = 0; if(canConnect(0, 1)){ - context.fillStyle = ssc1; + context.fillStyle = spikeColors[1]; context.fillRect(c*tileSize+(tileSize*.3), r*tileSize+(tileSize*.8), tileSize*.4, tileSize*.4); boltBool = true; } if(canConnect(0, -1) && !canConnect(0, 1)){ if(!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(1, -1)){} else{ - context.fillStyle = ssc1; + context.fillStyle = spikeColors[1]; context.fillRect(c*tileSize+(tileSize*.3), r*tileSize, tileSize*.4, tileSize*.4); boltBool = true; } @@ -2869,7 +2874,7 @@ function render() { if(canConnect(-1, 0) && !canConnect(0, 1)){ if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(-1, 1)){} else{ - context.fillStyle = ssc1; + context.fillStyle = spikeColors[1]; context.fillRect(c*tileSize, r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); boltBool = true; } @@ -2877,13 +2882,13 @@ function render() { if(canConnect(1, 0) && !canConnect(0, 1)){ if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(1, -1) && canConnect(1, 1)){} else{ - context.fillStyle = ssc1; + context.fillStyle = spikeColors[1]; context.fillRect(c*tileSize+(tileSize*.8), r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); boltBool = true; } } - context.fillStyle = ssc2; + context.fillStyle = spikeColors[2]; if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING ONE roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4,br:4}, true, false); boltBool = true; @@ -2960,12 +2965,12 @@ function render() { } function drawBolt(r, c){ - context.strokeStyle = bc; + context.strokeStyle = spikeColors[3]; context.beginPath(); context.arc(c*tileSize+(tileSize*.55), r*tileSize+(tileSize*.45), 4, -.7*Math.PI, .2*Math.PI); context.lineTo(c*tileSize+(tileSize*.45),r*tileSize+(tileSize*.35)); context.closePath(); - context.fillStyle = bc; + context.fillStyle = spikeColors[3]; context.fill(); context.stroke(); @@ -2974,7 +2979,7 @@ function render() { context.arc(c*tileSize+(tileSize*.48), r*tileSize+(tileSize*.52), 4, .2*Math.PI, -.75*Math.PI); //context.lineTo(c*tileSize+(tileSize*.4),r*tileSize+(tileSize*.6)); context.closePath(); - context.fillStyle = bc; + context.fillStyle = spikeColors[3]; context.fill(); context.stroke(); } @@ -3004,8 +3009,7 @@ function render() { rowcols.forEach(function(rowcol) { var r = rowcol.r + animationDisplacementRowcol.r; var c = rowcol.c + animationDisplacementRowcol.c; - context.fillStyle = blockForeground[block.id % blockForeground.length]; - if(surface == "rainbow") context.fillStyle = rainbowForeground[block.id % rainbowForeground.length]; + context.fillStyle = blockColors[0][block.id % blockColors[0].length]; drawTileOutlines2(r, c, isAlsoThisBlock, 0.3); function isAlsoThisBlock(dc, dr) { for (var i = 0; i < rowcols.length; i++) { From 6e6651e5016c00bb0a83e2bde37b38b2531eff3d Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 14:40:31 -0500 Subject: [PATCH 059/577] Update a.js --- a.js | 60 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/a.js b/a.js index d184771a..66ababe8 100644 --- a/a.js +++ b/a.js @@ -1608,18 +1608,22 @@ function isAnyCheatcodeEnabled() { !isGravityEnabled || !isCollisionEnabled ); } -var themeName = "Spring"; //themeCenter Gooby -var background, surface, material, blockColors, spikeColors, textStyle; +var themeName = "Spring"; //Gooby +var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle; var curlyOutline = false; var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; var bg2 = "rgba(254, 198, 145 * rgba(255, 192, 133"; var bg3 = "rgba(145, 254, 198 * rgba(117, 255, 192"; +var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; +var snakeColors2 = ["#f00", "#0f0", "#00f", "#ff0"]; +var snakeColors3 = ["#B92215", "#FBAB0B", "#C41560", "#FEFE37"]; + var fruitColors1 = ["#ff0066","#ff36a6","#ff6b1f","#ff9900","#ff2600"]; var fruitColors2 = ["black","black","black","black","black"]; -var spikeColors1 = ["#999", "#444", "#555", "#777"]; +var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spike, support, box, bolt var spikeColors2 = ["black", "black", "black", "black"]; var blockColors1 = [ @@ -1634,20 +1638,26 @@ var blockColors3 = [ ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"], ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] ]; +var blockColors4 = [ + ["#150612", "#a52e8b", "#990077", "#d917af", "#4d003c"], + ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] +]; -var textStyle1 = ["150px Impact", "#fdc122", "#fd0c0b"]; -var textStyle2 = ["150px Impact", "#00aaff", "#ffb3ec"]; +var textStyle1 = ["150px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose +var textStyle2 = ["150px Impact", "#5702c6", "#ff0098"]; +var textStyle3 = ["150px Impact", "#18d11f", "#fd0c0b"]; +var textStyle4 = ["150px Impact", "#ff0", "#f00"]; var themeCounter = 0; var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor //["sky",], - ["Spring", bg1, "#976537", "#95ff45", true, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], - ["Winter", bg1, "#30455B", "white", true, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], - ["Classic", bg1, "#844204", "#282", false, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], - ["Summer", bg2, "#976537", "#95ff45", true, blockColors3, spikeColors1, fruitColors1, "green", textStyle1], - ["Dream", bg3, "#00aaff", "#ffb3ec", true, blockColors1, spikeColors1, fruitColors2, "white", textStyle2], - ["Midnight Rainbow", "#070753", "black", "rainbow", false, blockColors2, spikeColors2, "white", "white", textStyle1] + ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], + ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], + ["Classic", bg1, "#844204", "#282", false, snakeColors2, blockColors1, spikeColors1, fruitColors1, "green", textStyle4], + ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3], + ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2], + ["Midnight Rainbow", "#070753", "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1] ]; @@ -2079,12 +2089,7 @@ function isAlive() { return countSnakes() > 0 && !isDead(); } -var snakeColors = [ - "#fd0c0b", - "#18d11f", - "#004cff", - "#fdc122", -]; + var snakeAltColors = [ "#ff6666", "#66ff66", @@ -2160,9 +2165,11 @@ function render() { background = themes[themeCounter][1]; material = themes[themeCounter][2]; surface = themes[themeCounter][3]; - blockColors = themes[themeCounter][5]; - spikeColors = themes[themeCounter][6]; - textStyle = themes[themeCounter][9]; + snakeColors = themes[themeCounter][5]; + blockColors = themes[themeCounter][6]; + spikeColors = themes[themeCounter][7]; + fruitColors = themes[themeCounter][8]; + textStyle = themes[themeCounter][10]; curlyOutline = themes[themeCounter][4]; if(background.substr(0,1) == "#") { @@ -2403,10 +2410,10 @@ function render() { case EXIT: //drawExit(r, c); var radiusFactor = isUneatenFruit() ? 0.7 : 1.2; - drawQuarterPie(r, c, radiusFactor, "#fd0c0b", 0); - drawQuarterPie(r, c, radiusFactor, "#18d11f", 1); - drawQuarterPie(r, c, radiusFactor, "#004cff", 2); - drawQuarterPie(r, c, radiusFactor, "#fdc122", 3); + drawQuarterPie(r, c, radiusFactor, snakeColors[0], 0); + drawQuarterPie(r, c, radiusFactor, snakeColors[1], 1); + drawQuarterPie(r, c, radiusFactor, snakeColors[2], 2); + drawQuarterPie(r, c, radiusFactor, snakeColors[3], 3); break; case PORTAL: drawCircle(r, c, 0.8, "#888"); @@ -2520,14 +2527,13 @@ function render() { drawBlock(object); break; case FRUIT: //Gooby - var fc = themes[themeCounter][7]; rowcol = getRowcol(level, object.locations[0]); var c = rowcol.c; var r = rowcol.r; var startC = c*tileSize+tileSize/2; var startR = r*tileSize+tileSize*.2; var resize = tileSize * 1.7; - context.fillStyle = fc[object.id % fc.length]; + context.fillStyle = fruitColors[object.id % fruitColors.length]; if(themeName != "Classic"){ if(surface == "rainbow") { context.fillStyle = "black"; @@ -2550,7 +2556,7 @@ function render() { context.moveTo(startC,startR); context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); - context.fillStyle = themes[themeCounter][8]; + context.fillStyle = themes[themeCounter][9]; context.fill(); } else drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); From e7df4e876754bda27a81b24eeb44280638f77371 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 19:48:46 -0500 Subject: [PATCH 060/577] Update a.js --- a.js | 91 ++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 58 insertions(+), 33 deletions(-) diff --git a/a.js b/a.js index 66ababe8..3aea3885 100644 --- a/a.js +++ b/a.js @@ -1618,7 +1618,7 @@ var bg3 = "rgba(145, 254, 198 * rgba(117, 255, 192"; var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; var snakeColors2 = ["#f00", "#0f0", "#00f", "#ff0"]; -var snakeColors3 = ["#B92215", "#FBAB0B", "#C41560", "#FEFE37"]; +var snakeColors3 = ["#BA145C", "#E91624", "#F75802", "#FEFE28"]; var fruitColors1 = ["#ff0066","#ff36a6","#ff6b1f","#ff9900","#ff2600"]; var fruitColors2 = ["black","black","black","black","black"]; @@ -1643,10 +1643,11 @@ var blockColors4 = [ ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] ]; -var textStyle1 = ["150px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose -var textStyle2 = ["150px Impact", "#5702c6", "#ff0098"]; -var textStyle3 = ["150px Impact", "#18d11f", "#fd0c0b"]; -var textStyle4 = ["150px Impact", "#ff0", "#f00"]; +var fontSize = tileSize*5; +var textStyle1 = ["" + fontSize + "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose +var textStyle2 = ["" + fontSize + "px Impact", "#5702c6", "#ff0098"]; +var textStyle3 = ["" + fontSize + "px Impact", "#18d11f", "#fd0c0b"]; +var textStyle4 = ["" + fontSize + "px Impact", "#ff0", "#f00"]; var themeCounter = 0; @@ -2159,9 +2160,9 @@ function render() { canvas.width = tileSize * level.width; canvas.height = tileSize * level.height; var context = canvas.getContext("2d"); //Gooby - - if(true){ - themeName = themes[themeCounter][0]; + + themeName = themes[themeCounter][0]; + if(themeName!="sky"){ background = themes[themeCounter][1]; material = themes[themeCounter][2]; surface = themes[themeCounter][3]; @@ -2629,8 +2630,21 @@ function render() { context.beginPath(); context.arc((c+1)*tileSize+tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); context.closePath(); - //tileColor = context.getImageData((c+1)*tileSize+tileSize/2, (r+1)*tileSize+tileSize/2, 1, 1); - //context.fillStyle = "rgba(" + tileColor.data[0] + ", " + tileColor.data[1] + ", " + tileColor.data[2] + ", " + tileColor.data[3] + ")"; + + var bgColor; + if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*')+2, background.length); + var r1, r2, b1, b2, g1, g2; + r1 = bgColor.substr(5, bgColor.indexOf(",")-5); + g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); + var shade = (r+1)*.03+.5; + if(shade>1) + shade = 1; + r2 = 255 + (r1-255) * shade; + g2 = 255 + (g1-255) * shade; + b2 = 255 + (b1-255) * shade; + context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; context.fill(); context.globalCompositeOperation = "source-over"; } @@ -2640,15 +2654,27 @@ function render() { context.beginPath(); context.arc(c*tileSize-tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); context.closePath(); - //tileColor = context.getImageData(c*tileSize-tileSize/2, (r+1)*tileSize+tileSize/2, 1, 1); - //alert(tileColor.data[0] + " " + tileColor.data[1] + " " + tileColor.data[2] + " " + tileColor.data[3] + ""); - //context.fillStyle = "rgba(" + tileColor.data[0] + ", " + tileColor.data[1] + ", " + tileColor.data[2] + ", " + tileColor.data[3] + ")"; + + var bgColor; + if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*')+2, background.length); + var r1, r2, b1, b2, g1, g2; + r1 = bgColor.substr(5, bgColor.indexOf(",")-5); + g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); + var shade = (r+1)*.03+.5; + if(shade>1) + shade = 1; + r2 = 255 + (r1-255) * shade; + g2 = 255 + (g1-255) * shade; + b2 = 255 + (b1-255) * shade; + context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; context.fill(); context.globalCompositeOperation = "source-over"; } } - function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { + function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { //Gooby if(surface != "rainbow") { context.fillStyle = surface; } @@ -2680,48 +2706,47 @@ function render() { var complementPixels = (1 - 2 * outlineThickness) * tileSize; - if (curlyOutline && !isOccupied(0, -1)){ //context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); //grass + if (curlyOutline && !isOccupied(0, -1)){ if(!isOccupied(-1, 0) && isOccupied(1, 0)){ context.beginPath(); - context.moveTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.25); + context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.3, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.4, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); context.lineTo(c*tileSize+tileSize, r*tileSize); context.lineTo(c*tileSize+tileSize*.2, r*tileSize); - context.arc(c*tileSize+tileSize*.2, r*tileSize+tileSize*.2, tileSize*.2, 1.5*Math.PI, .9*Math.PI, true); + context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); context.closePath(); } else if(isOccupied(-1, 0) && !isOccupied(1, 0)){ context.beginPath(); - context.moveTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.25); + context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); context.bezierCurveTo(c*tileSize+tileSize*.95, r*tileSize+tileSize*.3, c*tileSize+tileSize*.7, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.65, r*tileSize+tileSize*.3, c*tileSize+tileSize*.4, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.65, r*tileSize+tileSize*.4, c*tileSize+tileSize*.4, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); context.bezierCurveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.1, r*tileSize+tileSize*.4, c*tileSize, r*tileSize+tileSize*.2); context.lineTo(c*tileSize, r*tileSize); context.lineTo(c*tileSize+tileSize*.8, r*tileSize); - context.arc(c*tileSize+tileSize*.8, r*tileSize+tileSize*.2, tileSize*.2, 1.5*Math.PI, 2.1*Math.PI); + context.bezierCurveTo((c+1)*tileSize+tileSize*.2, r*tileSize-tileSize*.05, (c+1)*tileSize+tileSize*.15, r*tileSize+tileSize*.5, (c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.25); context.closePath(); } else if(!isOccupied(-1, 0) && !isOccupied(1, 0)){ context.beginPath(); - context.moveTo(c*tileSize+tileSize*.85, r*tileSize); + context.moveTo(c*tileSize+tileSize*.9, r*tileSize-tileSize*0); context.lineTo(c*tileSize+tileSize*.2, r*tileSize); - context.arc(c*tileSize+tileSize*.2, r*tileSize+tileSize*.2, tileSize*.2, 1.5*Math.PI, .9*Math.PI, true); + context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.3, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.4, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.1); - //context.arc(c*tileSize+tileSize*.8, r*tileSize+tileSize*.2, tileSize*.2, 1.5*Math.PI, 2.1*Math.PI); + context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.8, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); + context.bezierCurveTo((c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.4, (c+1)*tileSize+tileSize*.3, r*tileSize+tileSize*.3, (c+1)*tileSize, r*tileSize+tileSize*.02); context.closePath(); } else{ context.beginPath(); context.moveTo(c*tileSize, r*tileSize); context.lineTo(c*tileSize, r*tileSize+tileSize*.15); - context.bezierCurveTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.4, c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.3, c*tileSize+tileSize*.6, r*tileSize+tileSize*.3, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); context.lineTo(c*tileSize+tileSize, r*tileSize); context.closePath(); } @@ -2741,10 +2766,10 @@ function render() { function drawBushes(r, c, isOccupied){ if(!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)){ - context.shadowColor = "#666"; + /*context.shadowColor = "#666"; context.shadowOffsetX = -.5; context.shadowOffsetY = -.5; - context.shadowBlur = 1; + context.shadowBlur = 1;*/ context.beginPath(); context.moveTo((c+1)*tileSize, r*tileSize); @@ -2762,10 +2787,10 @@ function render() { } if(!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)){ - context.shadowColor = "#666"; + /*context.shadowColor = "#666"; context.shadowOffsetX = .5; context.shadowOffsetY = -.5; - context.shadowBlur = 1; + context.shadowBlur = 1;*/ context.beginPath(); context.moveTo(c*tileSize, r*tileSize); From dacef0e94636fc95dacc2878b0e94d03276cce57 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 19:56:18 -0500 Subject: [PATCH 061/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index 3aea3885..5fd6aa84 100644 --- a/a.js +++ b/a.js @@ -31,7 +31,7 @@ var SNAKE = "s"; var BLOCK = "b"; var FRUIT = "f"; -var tileSize = 30; +var tileSize = 29; var level; var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; var uneditStuff = {undoStack:[], redoStack:[], spanId:"editsSpan", undoButtonId:"uneditButton", redoButtonId:"reeditButton"}; From 1142d0c9af550ff1b0aa4ac30cfffb5bf0a605b8 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 19:57:05 -0500 Subject: [PATCH 062/577] Update a.js --- a.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/a.js b/a.js index 5fd6aa84..3aea3885 100644 --- a/a.js +++ b/a.js @@ -31,7 +31,7 @@ var SNAKE = "s"; var BLOCK = "b"; var FRUIT = "f"; -var tileSize = 29; +var tileSize = 30; var level; var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; var uneditStuff = {undoStack:[], redoStack:[], spanId:"editsSpan", undoButtonId:"uneditButton", redoButtonId:"reeditButton"}; From 5a55fc7c22e0f8b01bfcb2b707621c80f91eb183 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 20:10:03 -0500 Subject: [PATCH 063/577] Update a.js --- a.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/a.js b/a.js index 3aea3885..80270394 100644 --- a/a.js +++ b/a.js @@ -1631,8 +1631,8 @@ var blockColors1 = [ ["#853641","#963c84","#753d88","#5d3a96","#3a3990"] ]; var blockColors2 = [ - ["white"], - ["white"] + ["#f2f2f2"], + ["#f2f2f2"] ]; var blockColors3 = [ ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"], @@ -1646,7 +1646,7 @@ var blockColors4 = [ var fontSize = tileSize*5; var textStyle1 = ["" + fontSize + "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose var textStyle2 = ["" + fontSize + "px Impact", "#5702c6", "#ff0098"]; -var textStyle3 = ["" + fontSize + "px Impact", "#18d11f", "#fd0c0b"]; +var textStyle3 = ["" + fontSize + "px Impact", "#BA145C", "#F75802"]; var textStyle4 = ["" + fontSize + "px Impact", "#ff0", "#f00"]; var themeCounter = 0; From c0fe441425c71ca72fba17465f9ecbc2bdc5e3e4 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 20:17:34 -0500 Subject: [PATCH 064/577] Update a.js --- a.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/a.js b/a.js index 80270394..5c6e2a56 100644 --- a/a.js +++ b/a.js @@ -1615,6 +1615,7 @@ var curlyOutline = false; var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; var bg2 = "rgba(254, 198, 145 * rgba(255, 192, 133"; var bg3 = "rgba(145, 254, 198 * rgba(117, 255, 192"; +var bg4 = "rgba(7, 7, 83 * rgba(0, 0, 70"; var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; var snakeColors2 = ["#f00", "#0f0", "#00f", "#ff0"]; @@ -1658,7 +1659,7 @@ var themes = [ //name, background, material, surface, curlyOutline, blockColors ["Classic", bg1, "#844204", "#282", false, snakeColors2, blockColors1, spikeColors1, fruitColors1, "green", textStyle4], ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3], ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2], - ["Midnight Rainbow", "#070753", "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1] + ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1] ]; From ccb04b3e0df117e0d9afb393713bd98f3a74ae13 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:10:41 -0500 Subject: [PATCH 065/577] Create index2.html --- index2.html | 457 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 457 insertions(+) create mode 100644 index2.html diff --git a/index2.html b/index2.html new file mode 100644 index 00000000..e9d37ba5 --- /dev/null +++ b/index2.html @@ -0,0 +1,457 @@ + + + Snakefall + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SolutionLevelCreatorNote
    Disabilities Actthejoshwolfe
    Crashing Downthejoshwolfe
    Etch-a-sketchinukoblainc
    Fruit FallXeroOl
    Block ValleyCreator
    Block Valley 2Creator
    Spike MazeCreator
    Fruit MazeCreator
    Box BridgeCreator
    Please add animationsCreator
    The OrdealCreator
    Coral BlockCreator
    AdventureCreator
    Sky GridCreator
    Block TrainCreator
    Turn AroundCreator
    Turn Around 2Creator
    There and Back AgainCreator
    You Don't Have To Wait For AnimationsCreator
    KeyholeCreator
    Block Train 2Creator
    Fruit Maze 2Creator
    Tight SpaceCreator
    Floating FruitsCreator
    SkyscraperCreator
    Fruit Maze 3Creator
    Fruit Maze 4Creator
    Fruit Maze 5Creator
    Fruit Maze 6Creator
    DisarmCreator
    Level 1Creator
    Level 2Creator
    Bumpy RoadCreator
    Level 0 "Checkmark Underpass"Creator
    Level 1 "Hanging spikes"Creator
    Level 2 "Trap Mine"Creator
    Level 3 "The Servant"Creator
    Level 4 "Greed that goes well"Creator
    Level 5 "Collapse"Creator
    Level 6 "Decisions"Creator
    Level 1Creator
    NameCreator
    Level 2Creator
    Level 3Creator
    Level 3 2Creator
    Balancing ActCreator
    TempleCreator
    BasilicaCreator
    The BirdcageCreator
    The Birds UncagedCreator
    StrippedCreator
    SerpentineCreator
    The SawmillCreator
    The HardmillCreator
    Mine RescueCreator
    Plane CrashCreator
    Top ShelfCreator
    Top Shelf 2Creator
    PlinkoCreator
    The Puppet MasterCreator
    Rainbow BridgeCreator
    CastleCreator
    PerchCreator
    NameCreator
    + + + +# NoHatCoder Puzzles + +|Solution|Creator|Note| +|---|:---:|:---:| +|[Fruity Gap](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&9&14?*Q01002*K01*I01*301*104*Q0/s2?46&60&74&75/s0?48&62&61/f0?49/#replay=nmGTi8PB&2rur0l2ullul0uululullurr2luu*0r0rrrdrr2*2r0uluurrdllu*1r2rddl0ddl)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| +|[Bridge](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&16&24?*v0*51*z0*V04*h0111*40*51*00111*40*51*00111*40*51*00111*40*51*0011122*0022*51*k0/b0?160&136&112/b1?161&137&113/b2?186&185&184/s1?206&205/b3?210&209&208/#replay=nmGTi8PB&1rru*0rdlululurdrdlululurdrdlululurdrdlulullurrdrdlulllurrrdllullurrdllullurrdlulllurrrd*4lu)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| +|[Abyss](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&19&12?*M0*41*m0*01201*50201*D04*90100011*D011*H01*70111*R0/s2?77&76/s0?65&64/f0?115/#replay=nmGTi8PB&2r0rrd2rrrdllur0r2rr0rrul2u*0l0u*2ldrr2lulldlddrdrru0ulll2lluluuuruul)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| +|[Tube](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&13&16?*U0*81*001*30*01*001*5011*001*301011*00*51011*001*601*001*2011001*001011*00*01*0040*61*U0/f0?67/s2?71&72&73&74/s0?87&88&89/s1?152&151&150/f1?153/#replay=nmGTi8PB&*0lu1uu*0rdl2u*0rddd*4l0*2rurrddd*2l1ulllddl2urrurrd*0lurrr1uul2dr1lldluru*0r2u1dd2u*0ldd1r2l0ll1u0*0lddl1u*0lddl)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| +|[Tunnel](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&26?*o0*E1*J0111*J0111*J0111*J0111*I0*01*I0*01*I0*01*I0*01*I0*01*I0*01*504*M01*30101*J0*31*t0/s0?300&299&298&297/f0?309/s2?326&325&324&323/b0?352/#replay=nmGTi8PB&2rdrrrulldl0ulld*1rdllulllurrr2ll0drrurrrurrrulllurrdlll2ll0ll2l0llullldrr2u0r2rrdllluuu0*0uru2ll0lldrd*3l2uu*5l0*1ld2l)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| +|[Transport](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&20&28?*s01*F0111*101*F0101*101*A0*2101*101*A011011101*101*A01*201*101*A010011101*101*A011011101*101*D011101*101*D011101*101*D011101*101*C0*0101*10*51*22*2101*L01004*K0101*L0101*M02*u0/b0?232/b1?260/s2?288&287/s0?316&315&314&313/s1?344&343&342&341&340/#replay=nmGTi8PB&rrdll1r0l1urr*0ulldd2r1drr2ul0ll2lu*1ld*0rullurururrr1rrr2rr0urruurr2r0r2r0r2r0ru*0lurr2ululur0rr2rurrr0urru*0lurr1u0uru*3l1*4lu*4r0u*3r1rur2u1uu2l1l0r1lld0ur1rr0uu1ulldrdr2u1ur2*1rurr0ulu*1rdddrr1*0ulu*1r*0drr)|[edderiofer, NoHatCoder, & Gooby](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| + +# Avis Anguis Puzzles + +|Solution|Creator|Note| +|---|:---:|:---:| +|[Demo](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&49?*z0*z0*z0*z0*C0*32*b02*31*Z05002*21*d04001*S0*71*101*R015*61*1011*Q010*61*201*S0*51*3011*Y011*401*R01*201*501*R01*201*501*R0101*001*4011*C0*2100*410110111*401*F0*0100*71*801*H011222*61*801*R0*01*90111*Q0111*h011*h011*h011*z0*t0/b0?800&801/b1?657&660&709&758&807/b2?415&414&317&268/s2?809&810&761&712&663/s1?793&792/s0?751&752/f1?270/f0?368/#replay=nmGTi8PB&urrd*3l1*6r0uru*1rurru1u0r2llulluu*0lddruuru0uullluld*1lul2uldddllu*0lu*0rdrr1l2ul1ll2luuu1l2rrru*2ld1ur2r1r2ruruuuruuur1*3r2u*0r1ululur2rr1rr2ru1u*0rdrrr2u*0rddrrr0d*2r)|Terzalo| +|[Level A](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&14&12?11*30*11*401110004*10111*6011*6011*6011*001*1011*6011*50111*50111*6011*6011*50111*5011/b0?52&63&62&74&86&98&110&122&134&135&136&137&138&139&140&128&117&92&91&68&67&54/s2?76&64&65&66/f0?101/s1?124&123/#replay=nmGTi8PB&2drruullu1rurrururr2ldluu*0rururruuru1ulll2uu*2luu1luluul)|Connorses| +|[Level B](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&14&13?*D04*4011*7011*50*11*40*41*10*61*00111*60111*001100*11*40*11*50*01*0011100*6100*61000111/f0?30/s1?133&132&145&146/s0?136&137/#replay=nmGTi8PB&1r0l1uuruurrruullulluu*0rdd*0ldddru0u1u0rrr1rrruu0u1u0l1rrullull0ll1ull0luu1uuu)|Connorses| +|[Level 1](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&10&5?*a04414400100/f0?7/s2?26/s1?31&32/s0?38&37&36/#replay=nmGTi8PB&1ur2r1r2r0ul1ul2l0uu1u2uld1ld0ld)|CHz| +|[Level 2](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&8&7?*9041110111*A01110*D1/s0?9&8&7/s1?11&12/f1?33/f0?29/#replay=nmGTi8PB&1lu0rddllldrru*0rdll1lu0l1ru0uu1rrr0urrr)|CHz| +|[Level 3](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&12&14?*l01*901*901*9010011*50*11*B01*101*104*010*910*51/s1?47&46&45&44/b0?102&74&58&59&60&61&62/b1?132&118&104&90&76&75&131&129&128&114&100&86&72&73/s0?89&103&117&116/s2?94&95/#replay=nmGTi8PB&llddru1u*0lddrrulluruu*3r2ururu1rddr2l1uul2lu*4ldrr0rullu2dr0uruuulluu*5rulul1urruuulu*5lddrrd2u1dluuruul2llur1ur2u1u2l1l0ldl2u0l2r0uruu*2ldd2u0ruu2*0ru0rulluruu*2rddluuu1uurddrrur2*1r1*2r0rd*1r)|CHz| + +# GameBoy Puzzles + +|Solution|Creator|Note| +|---|:---:|:---:| +|[Level 1](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&16&20?*e0*010*01*70*010*01*504*l01*E02*Y0*21*A0*21*g0*61*90*11*B0*11*40/f0?68/f1?94/f2?222/s1?226&225&224/s2?248&247&246&245/#replay=nmGTi8PB&1*1r2urrruuu*0ruuulullddd*6lu*5r1ulluluu2u1r2uuuru1rurul2ururuuu1*7l2u*2ldddrrr*0uruurur*0u*5l1d2lllddd)|freeball1|| +|[Level 2](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&20?*z0*B0*11*0011*00*61*0011*00*11*5011*E011*E011*E011*204*7011*E011*P0*11*0011*00*61*0011*00*11*5011*E011*E011*50/f0?128/f1?131/f2?246/f3?253/s0?22&42&62/s5?76&77&57&37/#replay=nmGTi8PB&5*1ld*0lul*0u0*2r5r0u*0l5ullurrd*5ru*5l0llu*0rur5*0lu0rd*0rd*5ruuu5*Aruuu)|freeball1|| +|[Level 3](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&19&20?*z0*Y02002002002*N0*C1*00*C1*00*01*C0*0104*A0*01*C0*01*C0*01*C0*010202020202020202*01*C0*01*C0*01*C0*01*C0/b0?83&63&62&82/s0?21&22&23&24/s3?41&42/#replay=nmGTi8PB&3drrru0ldrruluruuurrrdd*2ruuld*1luulllddr3rrru0rruurrrdd*3ruuld*2luullldd3rrru0rrruu*4r3*1r0rrulu3rrrd*7lulld0l)|freeball1|| +|[Level 4](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&16&21?*z0*G01*404*V022*G02*E0*01*J0*51*301000*51*m0*01*C0*01*T0/s2?178&179&180&181&182/s3?118&139&160/f0?151/f1?264/#replay=nmGTi8PB&2lldlddd*0rullull3*2ldldrru*1rdllu*0luur2llluuullluurr3urrulld*1l2*0ulllurrr*0dlddrr3dluururruuururr*0u2*0rurr*0u)|freeball1|| +|[Level 5](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&20?*u011101*00102*401410001*1020100*0101110*01*5011*10*51001011*801*1011*D0111*501101000*0101*301*10*11*00100011*40111*10*01001*1011*001*301001001101*B0111*801*101110011000*1100*K1/s1?43&42&41/s2?23&22&21/b0?24&44&45&25/f0?123/#replay=nmGTi8PB&2u*1r1*3rddrrruu*0rull2drrrdrruurr1lurururuu*4lulluu*3rddlddrurruurulll2rdrrdlllullddlu*2ruuruu*1l1luullluu*1l2ldd*2l1u2uu*1lddrdr1l2uu1luulurrr2rrulldluluurru1urullulluuurrrddllulurruluuul2*0rurr1lu*0ruuluur2ullulu1ulll2urrruruu*3rururuu*4lulllulldd*0luu1luuu)|freeball1|| +|[Level 6](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&20?*b0*D1000*D1*z0*z0*w04*z0*K0/s2?123&103/s0?135&115/f0?155/f1?175/f2?143/f3?163/f4?185/f5?187/f6?190/f7?193/#replay=nmGTi8PB&2d*8rull0lll2*0l0lll2lll0*0l2lll0llur2urrr0rrr2rrr0rrr2ru*0ld0u*1l2luurr0urrr2rruurrr0dluruu*1r2uluul0ulllurrddruuluull2d)|freeball1|| +|[Level 7](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&20?00*C1*201*001104001*9011*s011101*8010011*001*9011001*60100021120001*401110*010111*R01*101*901*F01*c0111*h0/f0?27/s3?147&167&166&165/s1?152&172&173/b0?90&89&69&70/f1?272/f2?239/#replay=nmGTi8PB&1ulur3llurrdd*1ruuurruuuru*4l*0ulldddrruuulu*4r*0dlldddlldddrrr1drrull3ulll1llldrr3l1rurrruuulluurruuurrdddrrru*0lurrrd*0luuulluurruuurullluuu3luuur*0urruuurullluuu)|freeball1|| +|[Level 8](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&20?*z0*004*N0202*j01*2011*60111*D01110*01*80111*3011*O0111*X0111*X0111*80*91*00/s1?304&324/s0?305&325/f0?291/f1?247/f2?171/f3?179/f4?98/#replay=nmGTi8PB&rru*0ruru*1l1rrr0uuuluru*2rdll1u*0ru0u1*0l0*0lu1u0u1*0r0*0ru1u0u1u*4ruluuulur*0u*3lddr*0dluu0u1uu0rulluluuu1ruluu*0luu*0ruuurulluluuu)|freeball1|| +|[Level 9](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&20?*S011*E011*z00*21*4011*00*21*4011*H011*E011*a01*30202202000*0104*102*002000*01*10*61*60*61*Q0*61*10/s2?61&81&101/s0?63&83&103/f0?128/f1?132/f2?17/f3?332/#replay=nmGTi8PB&*2r2*1ru*2r0u*3rddllluu2rrulldrrrur0rurruu2u0r2rrruuululuuu0uu2ul*0dllddrddd*7luuurruurrddrrruurrddrruuruuu0luu*0l2urululu*3ldddrrruu*0l0*2lul2lulldddruu0u*0l2u*0ld)|freeball1|| +|[Level 10](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&21?*m01*c0*11*1011*50*110200011*B0*01*402*11000*0100222*00*11*O011*B01120111*202*301100111*202*3011*504*5011*B0*21*B0*21*B01*00111*901*00111/f0?58/f1?129/s1?285&286&287/s0?264&265&266&267&268/f2?183/#replay=nmGTi8PB&urrr1urrruu0*0u*1luuu*1rur*2dl1rul0l*1u1u*1lur0rrrullluu*5l1ull0lulu*0rurr1urrdllurrru*0r0*1r*2dlllururr1*0rdddllld*0l0rru*5l)|freeball1|| + +-------------------------------------- + +# Experimental Snakebird Puzzles + +|Solution|Creator|Note| +|---|:---:|:---:| +|Under Cover|[XeroOl](https://github.com/XeroOl)| +|Snake Filter|[XeroOl](https://github.com/XeroOl)| +|Platformway to Heaven|[thejoshwolfe](https://github.com/thejoshwolfe)| +|Under Cover 2|[XeroOl](https://github.com/XeroOl)| +|Low Clearance|[XeroOl](https://github.com/XeroOl)| +|Baited Trap|[XeroOl](https://github.com/XeroOl)| +|Gateway to Freedom|[LevelWorld](https://github.com/Fargogoosey)| +|House on Fire|[Gooby](https://github.com/jmdiamond3)| +|Underground|[Gooby](https://github.com/jmdiamond3)| From b2dcf9351e415c33c6b2f3f36b5a8b932548524c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:11:06 -0500 Subject: [PATCH 066/577] Rename index.html to framework.html --- index.html => framework.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename index.html => framework.html (100%) diff --git a/index.html b/framework.html similarity index 100% rename from index.html rename to framework.html From 4e2230afbbc4e0ca0993c8e7aa86fd90de9db39b Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:11:27 -0500 Subject: [PATCH 067/577] Rename index2.html to index.html --- index2.html => index.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename index2.html => index.html (100%) diff --git a/index2.html b/index.html similarity index 100% rename from index2.html rename to index.html From d192d05fbcf79a66d4a6cb7616d85ce80f60a048 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:14:33 -0500 Subject: [PATCH 068/577] Create format.css --- format.css | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 format.css diff --git a/format.css b/format.css new file mode 100644 index 00000000..3511f8bb --- /dev/null +++ b/format.css @@ -0,0 +1,25 @@ +table{ + width: 50%; + font-family: Garamond; + color: black; + counter-reset: rowNumber; + margin-left: 25%; + margin-right: 25%; +} + +table tr:not(:first-child){ + counter-increment: rowNumber; +} + +table tr td:first-child::before { + content: counter(rowNumber); + min-width: 1em; + margin-right: 0.5em; +} + +td{ + text-align: center; +} + +a{ +} From 3446978b8b0d7e597c49b179686e7cda8dd730dc Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:14:47 -0500 Subject: [PATCH 069/577] Update index.html --- index.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/index.html b/index.html index e9d37ba5..055e3e73 100644 --- a/index.html +++ b/index.html @@ -5,6 +5,8 @@ + + From 4cb5bf26d95571b3b89e51870193ed27576c248a Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:25:19 -0500 Subject: [PATCH 070/577] Update index.html --- index.html | 272 ++++++++++++++++++++++++++--------------------------- 1 file changed, 136 insertions(+), 136 deletions(-) diff --git a/index.html b/index.html index 055e3e73..0e885373 100644 --- a/index.html +++ b/index.html @@ -17,158 +17,158 @@ - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -197,98 +197,98 @@ - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -299,92 +299,92 @@ - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -409,38 +409,38 @@ |Solution|Creator|Note| |---|:---:|:---:| -|[Fruity Gap](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&9&14?*Q01002*K01*I01*301*104*Q0/s2?46&60&74&75/s0?48&62&61/f0?49/#replay=nmGTi8PB&2rur0l2ullul0uululullurr2luu*0r0rrrdrr2*2r0uluurrdllu*1r2rddl0ddl)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| -|[Bridge](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&16&24?*v0*51*z0*V04*h0111*40*51*00111*40*51*00111*40*51*00111*40*51*0011122*0022*51*k0/b0?160&136&112/b1?161&137&113/b2?186&185&184/s1?206&205/b3?210&209&208/#replay=nmGTi8PB&1rru*0rdlululurdrdlululurdrdlululurdrdlulullurrdrdlulllurrrdllullurrdllullurrdlulllurrrd*4lu)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| -|[Abyss](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&19&12?*M0*41*m0*01201*50201*D04*90100011*D011*H01*70111*R0/s2?77&76/s0?65&64/f0?115/#replay=nmGTi8PB&2r0rrd2rrrdllur0r2rr0rrul2u*0l0u*2ldrr2lulldlddrdrru0ulll2lluluuuruul)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| -|[Tube](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&13&16?*U0*81*001*30*01*001*5011*001*301011*00*51011*001*601*001*2011001*001011*00*01*0040*61*U0/f0?67/s2?71&72&73&74/s0?87&88&89/s1?152&151&150/f1?153/#replay=nmGTi8PB&*0lu1uu*0rdl2u*0rddd*4l0*2rurrddd*2l1ulllddl2urrurrd*0lurrr1uul2dr1lldluru*0r2u1dd2u*0ldd1r2l0ll1u0*0lddl1u*0lddl)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| -|[Tunnel](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&26?*o0*E1*J0111*J0111*J0111*J0111*I0*01*I0*01*I0*01*I0*01*I0*01*I0*01*504*M01*30101*J0*31*t0/s0?300&299&298&297/f0?309/s2?326&325&324&323/b0?352/#replay=nmGTi8PB&2rdrrrulldl0ulld*1rdllulllurrr2ll0drrurrrurrrulllurrdlll2ll0ll2l0llullldrr2u0r2rrdllluuu0*0uru2ll0lldrd*3l2uu*5l0*1ld2l)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| -|[Transport](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&20&28?*s01*F0111*101*F0101*101*A0*2101*101*A011011101*101*A01*201*101*A010011101*101*A011011101*101*D011101*101*D011101*101*D011101*101*C0*0101*10*51*22*2101*L01004*K0101*L0101*M02*u0/b0?232/b1?260/s2?288&287/s0?316&315&314&313/s1?344&343&342&341&340/#replay=nmGTi8PB&rrdll1r0l1urr*0ulldd2r1drr2ul0ll2lu*1ld*0rullurururrr1rrr2rr0urruurr2r0r2r0r2r0ru*0lurr2ululur0rr2rurrr0urru*0lurr1u0uru*3l1*4lu*4r0u*3r1rur2u1uu2l1l0r1lld0ur1rr0uu1ulldrdr2u1ur2*1rurr0ulu*1rdddrr1*0ulu*1r*0drr)|[edderiofer, NoHatCoder, & Gooby](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| +|[Fruity Gap](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&9&14?*Q01002*K01*I01*301*104*Q0/s2?46&60&74&75/s0?48&62&61/f0?49/#replay=nmGTi8PB&2rur0l2ullul0uululullurr2luu*0r0rrrdrr2*2r0uluurrdllu*1r2rddl0ddl)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| +|[Bridge](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&16&24?*v0*51*z0*V04*h0111*40*51*00111*40*51*00111*40*51*00111*40*51*0011122*0022*51*k0/b0?160&136&112/b1?161&137&113/b2?186&185&184/s1?206&205/b3?210&209&208/#replay=nmGTi8PB&1rru*0rdlululurdrdlululurdrdlululurdrdlulullurrdrdlulllurrrdllullurrdllullurrdlulllurrrd*4lu)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| +|[Abyss](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&19&12?*M0*41*m0*01201*50201*D04*90100011*D011*H01*70111*R0/s2?77&76/s0?65&64/f0?115/#replay=nmGTi8PB&2r0rrd2rrrdllur0r2rr0rrul2u*0l0u*2ldrr2lulldlddrdrru0ulll2lluluuuruul)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| +|[Tube](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&13&16?*U0*81*001*30*01*001*5011*001*301011*00*51011*001*601*001*2011001*001011*00*01*0040*61*U0/f0?67/s2?71&72&73&74/s0?87&88&89/s1?152&151&150/f1?153/#replay=nmGTi8PB&*0lu1uu*0rdl2u*0rddd*4l0*2rurrddd*2l1ulllddl2urrurrd*0lurrr1uul2dr1lldluru*0r2u1dd2u*0ldd1r2l0ll1u0*0lddl1u*0lddl)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| +|[Tunnel](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&26?*o0*E1*J0111*J0111*J0111*J0111*I0*01*I0*01*I0*01*I0*01*I0*01*I0*01*504*M01*30101*J0*31*t0/s0?300&299&298&297/f0?309/s2?326&325&324&323/b0?352/#replay=nmGTi8PB&2rdrrrulldl0ulld*1rdllulllurrr2ll0drrurrrurrrulllurrdlll2ll0ll2l0llullldrr2u0r2rrdllluuu0*0uru2ll0lldrd*3l2uu*5l0*1ld2l)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| +|[Transport](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&20&28?*s01*F0111*101*F0101*101*A0*2101*101*A011011101*101*A01*201*101*A010011101*101*A011011101*101*D011101*101*D011101*101*D011101*101*C0*0101*10*51*22*2101*L01004*K0101*L0101*M02*u0/b0?232/b1?260/s2?288&287/s0?316&315&314&313/s1?344&343&342&341&340/#replay=nmGTi8PB&rrdll1r0l1urr*0ulldd2r1drr2ul0ll2lu*1ld*0rullurururrr1rrr2rr0urruurr2r0r2r0r2r0ru*0lurr2ululur0rr2rurrr0urru*0lurr1u0uru*3l1*4lu*4r0u*3r1rur2u1uu2l1l0r1lld0ur1rr0uu1ulldrdr2u1ur2*1rurr0ulu*1rdddrr1*0ulu*1r*0drr)|[edderiofer, NoHatCoder, & Gooby](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| # Avis Anguis Puzzles |Solution|Creator|Note| |---|:---:|:---:| -|[Demo](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&27&49?*z0*z0*z0*z0*C0*32*b02*31*Z05002*21*d04001*S0*71*101*R015*61*1011*Q010*61*201*S0*51*3011*Y011*401*R01*201*501*R01*201*501*R0101*001*4011*C0*2100*410110111*401*F0*0100*71*801*H011222*61*801*R0*01*90111*Q0111*h011*h011*h011*z0*t0/b0?800&801/b1?657&660&709&758&807/b2?415&414&317&268/s2?809&810&761&712&663/s1?793&792/s0?751&752/f1?270/f0?368/#replay=nmGTi8PB&urrd*3l1*6r0uru*1rurru1u0r2llulluu*0lddruuru0uullluld*1lul2uldddllu*0lu*0rdrr1l2ul1ll2luuu1l2rrru*2ld1ur2r1r2ruruuuruuur1*3r2u*0r1ululur2rr1rr2ru1u*0rdrrr2u*0rddrrr0d*2r)|Terzalo| -|[Level A](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&14&12?11*30*11*401110004*10111*6011*6011*6011*001*1011*6011*50111*50111*6011*6011*50111*5011/b0?52&63&62&74&86&98&110&122&134&135&136&137&138&139&140&128&117&92&91&68&67&54/s2?76&64&65&66/f0?101/s1?124&123/#replay=nmGTi8PB&2drruullu1rurrururr2ldluu*0rururruuru1ulll2uu*2luu1luluul)|Connorses| -|[Level B](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&14&13?*D04*4011*7011*50*11*40*41*10*61*00111*60111*001100*11*40*11*50*01*0011100*6100*61000111/f0?30/s1?133&132&145&146/s0?136&137/#replay=nmGTi8PB&1r0l1uuruurrruullulluu*0rdd*0ldddru0u1u0rrr1rrruu0u1u0l1rrullull0ll1ull0luu1uuu)|Connorses| -|[Level 1](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&10&5?*a04414400100/f0?7/s2?26/s1?31&32/s0?38&37&36/#replay=nmGTi8PB&1ur2r1r2r0ul1ul2l0uu1u2uld1ld0ld)|CHz| -|[Level 2](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&8&7?*9041110111*A01110*D1/s0?9&8&7/s1?11&12/f1?33/f0?29/#replay=nmGTi8PB&1lu0rddllldrru*0rdll1lu0l1ru0uu1rrr0urrr)|CHz| -|[Level 3](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&12&14?*l01*901*901*9010011*50*11*B01*101*104*010*910*51/s1?47&46&45&44/b0?102&74&58&59&60&61&62/b1?132&118&104&90&76&75&131&129&128&114&100&86&72&73/s0?89&103&117&116/s2?94&95/#replay=nmGTi8PB&llddru1u*0lddrrulluruu*3r2ururu1rddr2l1uul2lu*4ldrr0rullu2dr0uruuulluu*5rulul1urruuulu*5lddrrd2u1dluuruul2llur1ur2u1u2l1l0ldl2u0l2r0uruu*2ldd2u0ruu2*0ru0rulluruu*2rddluuu1uurddrrur2*1r1*2r0rd*1r)|CHz| +|[Demo](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&27&49?*z0*z0*z0*z0*C0*32*b02*31*Z05002*21*d04001*S0*71*101*R015*61*1011*Q010*61*201*S0*51*3011*Y011*401*R01*201*501*R01*201*501*R0101*001*4011*C0*2100*410110111*401*F0*0100*71*801*H011222*61*801*R0*01*90111*Q0111*h011*h011*h011*z0*t0/b0?800&801/b1?657&660&709&758&807/b2?415&414&317&268/s2?809&810&761&712&663/s1?793&792/s0?751&752/f1?270/f0?368/#replay=nmGTi8PB&urrd*3l1*6r0uru*1rurru1u0r2llulluu*0lddruuru0uullluld*1lul2uldddllu*0lu*0rdrr1l2ul1ll2luuu1l2rrru*2ld1ur2r1r2ruruuuruuur1*3r2u*0r1ululur2rr1rr2ru1u*0rdrrr2u*0rddrrr0d*2r)|Terzalo| +|[Level A](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&14&12?11*30*11*401110004*10111*6011*6011*6011*001*1011*6011*50111*50111*6011*6011*50111*5011/b0?52&63&62&74&86&98&110&122&134&135&136&137&138&139&140&128&117&92&91&68&67&54/s2?76&64&65&66/f0?101/s1?124&123/#replay=nmGTi8PB&2drruullu1rurrururr2ldluu*0rururruuru1ulll2uu*2luu1luluul)|Connorses| +|[Level B](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&14&13?*D04*4011*7011*50*11*40*41*10*61*00111*60111*001100*11*40*11*50*01*0011100*6100*61000111/f0?30/s1?133&132&145&146/s0?136&137/#replay=nmGTi8PB&1r0l1uuruurrruullulluu*0rdd*0ldddru0u1u0rrr1rrruu0u1u0l1rrullull0ll1ull0luu1uuu)|Connorses| +|[Level 1](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&10&5?*a04414400100/f0?7/s2?26/s1?31&32/s0?38&37&36/#replay=nmGTi8PB&1ur2r1r2r0ul1ul2l0uu1u2uld1ld0ld)|CHz| +|[Level 2](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&8&7?*9041110111*A01110*D1/s0?9&8&7/s1?11&12/f1?33/f0?29/#replay=nmGTi8PB&1lu0rddllldrru*0rdll1lu0l1ru0uu1rrr0urrr)|CHz| +|[Level 3](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&12&14?*l01*901*901*9010011*50*11*B01*101*104*010*910*51/s1?47&46&45&44/b0?102&74&58&59&60&61&62/b1?132&118&104&90&76&75&131&129&128&114&100&86&72&73/s0?89&103&117&116/s2?94&95/#replay=nmGTi8PB&llddru1u*0lddrrulluruu*3r2ururu1rddr2l1uul2lu*4ldrr0rullu2dr0uruuulluu*5rulul1urruuulu*5lddrrd2u1dluuruul2llur1ur2u1u2l1l0ldl2u0l2r0uruu*2ldd2u0ruu2*0ru0rulluruu*2rddluuu1uurddrrur2*1r1*2r0rd*1r)|CHz| # GameBoy Puzzles |Solution|Creator|Note| |---|:---:|:---:| -|[Level 1](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&16&20?*e0*010*01*70*010*01*504*l01*E02*Y0*21*A0*21*g0*61*90*11*B0*11*40/f0?68/f1?94/f2?222/s1?226&225&224/s2?248&247&246&245/#replay=nmGTi8PB&1*1r2urrruuu*0ruuulullddd*6lu*5r1ulluluu2u1r2uuuru1rurul2ururuuu1*7l2u*2ldddrrr*0uruurur*0u*5l1d2lllddd)|freeball1|| -|[Level 2](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&20?*z0*B0*11*0011*00*61*0011*00*11*5011*E011*E011*E011*204*7011*E011*P0*11*0011*00*61*0011*00*11*5011*E011*E011*50/f0?128/f1?131/f2?246/f3?253/s0?22&42&62/s5?76&77&57&37/#replay=nmGTi8PB&5*1ld*0lul*0u0*2r5r0u*0l5ullurrd*5ru*5l0llu*0rur5*0lu0rd*0rd*5ruuu5*Aruuu)|freeball1|| -|[Level 3](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&19&20?*z0*Y02002002002*N0*C1*00*C1*00*01*C0*0104*A0*01*C0*01*C0*01*C0*010202020202020202*01*C0*01*C0*01*C0*01*C0/b0?83&63&62&82/s0?21&22&23&24/s3?41&42/#replay=nmGTi8PB&3drrru0ldrruluruuurrrdd*2ruuld*1luulllddr3rrru0rruurrrdd*3ruuld*2luullldd3rrru0rrruu*4r3*1r0rrulu3rrrd*7lulld0l)|freeball1|| -|[Level 4](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&16&21?*z0*G01*404*V022*G02*E0*01*J0*51*301000*51*m0*01*C0*01*T0/s2?178&179&180&181&182/s3?118&139&160/f0?151/f1?264/#replay=nmGTi8PB&2lldlddd*0rullull3*2ldldrru*1rdllu*0luur2llluuullluurr3urrulld*1l2*0ulllurrr*0dlddrr3dluururruuururr*0u2*0rurr*0u)|freeball1|| -|[Level 5](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&20?*u011101*00102*401410001*1020100*0101110*01*5011*10*51001011*801*1011*D0111*501101000*0101*301*10*11*00100011*40111*10*01001*1011*001*301001001101*B0111*801*101110011000*1100*K1/s1?43&42&41/s2?23&22&21/b0?24&44&45&25/f0?123/#replay=nmGTi8PB&2u*1r1*3rddrrruu*0rull2drrrdrruurr1lurururuu*4lulluu*3rddlddrurruurulll2rdrrdlllullddlu*2ruuruu*1l1luullluu*1l2ldd*2l1u2uu*1lddrdr1l2uu1luulurrr2rrulldluluurru1urullulluuurrrddllulurruluuul2*0rurr1lu*0ruuluur2ullulu1ulll2urrruruu*3rururuu*4lulllulldd*0luu1luuu)|freeball1|| -|[Level 6](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&20?*b0*D1000*D1*z0*z0*w04*z0*K0/s2?123&103/s0?135&115/f0?155/f1?175/f2?143/f3?163/f4?185/f5?187/f6?190/f7?193/#replay=nmGTi8PB&2d*8rull0lll2*0l0lll2lll0*0l2lll0llur2urrr0rrr2rrr0rrr2ru*0ld0u*1l2luurr0urrr2rruurrr0dluruu*1r2uluul0ulllurrddruuluull2d)|freeball1|| -|[Level 7](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&20?00*C1*201*001104001*9011*s011101*8010011*001*9011001*60100021120001*401110*010111*R01*101*901*F01*c0111*h0/f0?27/s3?147&167&166&165/s1?152&172&173/b0?90&89&69&70/f1?272/f2?239/#replay=nmGTi8PB&1ulur3llurrdd*1ruuurruuuru*4l*0ulldddrruuulu*4r*0dlldddlldddrrr1drrull3ulll1llldrr3l1rurrruuulluurruuurrdddrrru*0lurrrd*0luuulluurruuurullluuu3luuur*0urruuurullluuu)|freeball1|| -|[Level 8](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&20?*z0*004*N0202*j01*2011*60111*D01110*01*80111*3011*O0111*X0111*X0111*80*91*00/s1?304&324/s0?305&325/f0?291/f1?247/f2?171/f3?179/f4?98/#replay=nmGTi8PB&rru*0ruru*1l1rrr0uuuluru*2rdll1u*0ru0u1*0l0*0lu1u0u1*0r0*0ru1u0u1u*4ruluuulur*0u*3lddr*0dluu0u1uu0rulluluuu1ruluu*0luu*0ruuurulluluuu)|freeball1|| -|[Level 9](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&20?*S011*E011*z00*21*4011*00*21*4011*H011*E011*a01*30202202000*0104*102*002000*01*10*61*60*61*Q0*61*10/s2?61&81&101/s0?63&83&103/f0?128/f1?132/f2?17/f3?332/#replay=nmGTi8PB&*2r2*1ru*2r0u*3rddllluu2rrulldrrrur0rurruu2u0r2rrruuululuuu0uu2ul*0dllddrddd*7luuurruurrddrrruurrddrruuruuu0luu*0l2urululu*3ldddrrruu*0l0*2lul2lulldddruu0u*0l2u*0ld)|freeball1|| -|[Level 10](https://jmdiamond3.github.io/Snakefall-Redesign/#level=HyRr4JK1&18&21?*m01*c0*11*1011*50*110200011*B0*01*402*11000*0100222*00*11*O011*B01120111*202*301100111*202*3011*504*5011*B0*21*B0*21*B01*00111*901*00111/f0?58/f1?129/s1?285&286&287/s0?264&265&266&267&268/f2?183/#replay=nmGTi8PB&urrr1urrruu0*0u*1luuu*1rur*2dl1rul0l*1u1u*1lur0rrrullluu*5l1ull0lulu*0rurr1urrdllurrru*0r0*1r*2dlllururr1*0rdddllld*0l0rru*5l)|freeball1|| +|[Level 1](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&16&20?*e0*010*01*70*010*01*504*l01*E02*Y0*21*A0*21*g0*61*90*11*B0*11*40/f0?68/f1?94/f2?222/s1?226&225&224/s2?248&247&246&245/#replay=nmGTi8PB&1*1r2urrruuu*0ruuulullddd*6lu*5r1ulluluu2u1r2uuuru1rurul2ururuuu1*7l2u*2ldddrrr*0uruurur*0u*5l1d2lllddd)|freeball1|| +|[Level 2](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&20?*z0*B0*11*0011*00*61*0011*00*11*5011*E011*E011*E011*204*7011*E011*P0*11*0011*00*61*0011*00*11*5011*E011*E011*50/f0?128/f1?131/f2?246/f3?253/s0?22&42&62/s5?76&77&57&37/#replay=nmGTi8PB&5*1ld*0lul*0u0*2r5r0u*0l5ullurrd*5ru*5l0llu*0rur5*0lu0rd*0rd*5ruuu5*Aruuu)|freeball1|| +|[Level 3](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&19&20?*z0*Y02002002002*N0*C1*00*C1*00*01*C0*0104*A0*01*C0*01*C0*01*C0*010202020202020202*01*C0*01*C0*01*C0*01*C0/b0?83&63&62&82/s0?21&22&23&24/s3?41&42/#replay=nmGTi8PB&3drrru0ldrruluruuurrrdd*2ruuld*1luulllddr3rrru0rruurrrdd*3ruuld*2luullldd3rrru0rrruu*4r3*1r0rrulu3rrrd*7lulld0l)|freeball1|| +|[Level 4](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&16&21?*z0*G01*404*V022*G02*E0*01*J0*51*301000*51*m0*01*C0*01*T0/s2?178&179&180&181&182/s3?118&139&160/f0?151/f1?264/#replay=nmGTi8PB&2lldlddd*0rullull3*2ldldrru*1rdllu*0luur2llluuullluurr3urrulld*1l2*0ulllurrr*0dlddrr3dluururruuururr*0u2*0rurr*0u)|freeball1|| +|[Level 5](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&20?*u011101*00102*401410001*1020100*0101110*01*5011*10*51001011*801*1011*D0111*501101000*0101*301*10*11*00100011*40111*10*01001*1011*001*301001001101*B0111*801*101110011000*1100*K1/s1?43&42&41/s2?23&22&21/b0?24&44&45&25/f0?123/#replay=nmGTi8PB&2u*1r1*3rddrrruu*0rull2drrrdrruurr1lurururuu*4lulluu*3rddlddrurruurulll2rdrrdlllullddlu*2ruuruu*1l1luullluu*1l2ldd*2l1u2uu*1lddrdr1l2uu1luulurrr2rrulldluluurru1urullulluuurrrddllulurruluuul2*0rurr1lu*0ruuluur2ullulu1ulll2urrruruu*3rururuu*4lulllulldd*0luu1luuu)|freeball1|| +|[Level 6](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&20?*b0*D1000*D1*z0*z0*w04*z0*K0/s2?123&103/s0?135&115/f0?155/f1?175/f2?143/f3?163/f4?185/f5?187/f6?190/f7?193/#replay=nmGTi8PB&2d*8rull0lll2*0l0lll2lll0*0l2lll0llur2urrr0rrr2rrr0rrr2ru*0ld0u*1l2luurr0urrr2rruurrr0dluruu*1r2uluul0ulllurrddruuluull2d)|freeball1|| +|[Level 7](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&20?00*C1*201*001104001*9011*s011101*8010011*001*9011001*60100021120001*401110*010111*R01*101*901*F01*c0111*h0/f0?27/s3?147&167&166&165/s1?152&172&173/b0?90&89&69&70/f1?272/f2?239/#replay=nmGTi8PB&1ulur3llurrdd*1ruuurruuuru*4l*0ulldddrruuulu*4r*0dlldddlldddrrr1drrull3ulll1llldrr3l1rurrruuulluurruuurrdddrrru*0lurrrd*0luuulluurruuurullluuu3luuur*0urruuurullluuu)|freeball1|| +|[Level 8](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&20?*z0*004*N0202*j01*2011*60111*D01110*01*80111*3011*O0111*X0111*X0111*80*91*00/s1?304&324/s0?305&325/f0?291/f1?247/f2?171/f3?179/f4?98/#replay=nmGTi8PB&rru*0ruru*1l1rrr0uuuluru*2rdll1u*0ru0u1*0l0*0lu1u0u1*0r0*0ru1u0u1u*4ruluuulur*0u*3lddr*0dluu0u1uu0rulluluuu1ruluu*0luu*0ruuurulluluuu)|freeball1|| +|[Level 9](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&20?*S011*E011*z00*21*4011*00*21*4011*H011*E011*a01*30202202000*0104*102*002000*01*10*61*60*61*Q0*61*10/s2?61&81&101/s0?63&83&103/f0?128/f1?132/f2?17/f3?332/#replay=nmGTi8PB&*2r2*1ru*2r0u*3rddllluu2rrulldrrrur0rurruu2u0r2rrruuululuuu0uu2ul*0dllddrddd*7luuurruurrddrrruurrddrruuruuu0luu*0l2urululu*3ldddrrruu*0l0*2lul2lulldddruu0u*0l2u*0ld)|freeball1|| +|[Level 10](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&21?*m01*c0*11*1011*50*110200011*B0*01*402*11000*0100222*00*11*O011*B01120111*202*301100111*202*3011*504*5011*B0*21*B0*21*B01*00111*901*00111/f0?58/f1?129/s1?285&286&287/s0?264&265&266&267&268/f2?183/#replay=nmGTi8PB&urrr1urrruu0*0u*1luuu*1rur*2dl1rul0l*1u1u*1lur0rrrullluu*5l1ull0lulu*0rurr1urrdllurrru*0r0*1r*2dlllururr1*0rdddllld*0l0rru*5l)|freeball1|| -------------------------------------- From f2208a07aaeef44b7129b105fcdbcf49560dd8ea Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:26:43 -0500 Subject: [PATCH 071/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 0e885373..189cf4bf 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ Snakefall - + From d0360b61ef891c096bd3f3dfa83c5ab0ffaeccf3 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:41:24 -0500 Subject: [PATCH 072/577] Update format.css --- format.css | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/format.css b/format.css index 3511f8bb..d5a0b940 100644 --- a/format.css +++ b/format.css @@ -1,10 +1,14 @@ table{ width: 50%; - font-family: Garamond; - color: black; + font-family: Palatino; counter-reset: rowNumber; margin-left: 25%; margin-right: 25%; + border-collapse: collapse; +} + +tr{ + height: 30px; } table tr:not(:first-child){ @@ -22,4 +26,17 @@ td{ } a{ + color: black; + text-decoration: none; +} + +td:hover{ + background-color: gainsboro; +} + +div{ + width: 100%; + text-align: center; + font-family: Impact; + font-size: 100px; } From 15a2a5fee2a8e2485878106242a5f13e52053485 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:41:43 -0500 Subject: [PATCH 073/577] Update index.html --- index.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.html b/index.html index 189cf4bf..9c20313a 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ Snakefall - + @@ -9,6 +9,7 @@ +
    SnakeFall Redesign
    Note
    Disabilities ActDisabilities Act thejoshwolfe
    Crashing DownCrashing Down thejoshwolfe
    Etch-a-sketchEtch-a-sketch inukoblainc
    Fruit FallFruit Fall XeroOl
    Block ValleyBlock Valley Creator
    Block Valley 2Block Valley 2 Creator
    Spike MazeSpike Maze Creator
    Fruit MazeFruit Maze Creator
    Box BridgeBox Bridge Creator
    Please add animationsPlease add animations Creator
    The OrdealThe Ordeal Creator
    Coral BlockCoral Block Creator
    AdventureAdventure Creator
    Sky GridSky Grid Creator
    Block TrainBlock Train Creator
    Turn AroundTurn Around Creator
    Turn Around 2Turn Around 2 Creator
    There and Back AgainThere and Back Again Creator
    You Don't Have To Wait For AnimationsYou Don't Have To Wait For Animations Creator
    KeyholeKeyhole Creator
    Block Train 2Block Train 2 Creator
    Fruit Maze 2Fruit Maze 2 Creator
    Tight SpaceTight Space Creator
    Floating FruitsFloating Fruits Creator
    SkyscraperSkyscraper Creator
    Fruit Maze 3Fruit Maze 3 Creator
    Level 1Level 1 Creator
    Level 2Level 2 Creator
    Bumpy RoadBumpy Road Creator
    Level 0 "Checkmark Underpass"Level 0 "Checkmark Underpass" Creator
    Level 1 "Hanging spikes"Level 1 "Hanging spikes" Creator
    Level 2 "Trap Mine"Level 2 "Trap Mine" Creator
    Level 3 "The Servant"Level 3 "The Servant" Creator
    Level 4 "Greed that goes well"Level 4 "Greed that goes well" Creator
    Level 5 "Collapse"Level 5 "Collapse" Creator
    Level 6 "Decisions"Level 6 "Decisions" Creator
    Level 1Level 1 Creator
    NameName Creator
    Level 2Level 2 Creator
    Level 3Level 3 Creator
    Level 3 2Level 3 2 Creator
    Balancing ActBalancing Act Creator
    BasilicaBasilica Creator
    The BirdcageThe Birdcage Creator
    The Birds UncagedThe Birds Uncaged Creator
    StrippedStripped Creator
    SerpentineSerpentine Creator
    The SawmillThe Sawmill Creator
    The HardmillThe Hardmill Creator
    Mine RescueMine Rescue Creator
    Plane CrashPlane Crash Creator
    Top ShelfTop Shelf Creator
    Top Shelf 2Top Shelf 2 Creator
    PlinkoPlinko Creator
    The Puppet MasterThe Puppet Master Creator
    Rainbow BridgeRainbow Bridge Creator
    CastleCastle Creator
    From fd2219261351be28e6644519751b0ba08cd76cc8 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:42:09 -0500 Subject: [PATCH 074/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 9c20313a..c8803072 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ Snakefall - + From ccda64b39938ca166b4973ba932b20029ccc5cad Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:42:32 -0500 Subject: [PATCH 075/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index c8803072..d7a6bec1 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ Snakefall - + From 426701ada0d14680961e0c435be4296f47c8bd64 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:58:23 -0500 Subject: [PATCH 076/577] Update format.css --- format.css | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/format.css b/format.css index d5a0b940..42783186 100644 --- a/format.css +++ b/format.css @@ -1,6 +1,9 @@ +body{ + font-family: Palatino; +} + table{ width: 50%; - font-family: Palatino; counter-reset: rowNumber; margin-left: 25%; margin-right: 25%; @@ -34,9 +37,25 @@ td:hover{ background-color: gainsboro; } -div{ +#title{ width: 100%; text-align: center; font-family: Impact; font-size: 100px; + margin-bottom: 20px; +} + +.topLink{ + display: block; + margin-bottom: 20px; + border: 1px solid black; + padding: 10px; +} + +#top{ + width: 30%; + margin-left: 35%; + margin-right: 35%; + text-align: center; + margin-bottom: 20px; } From f87f302a4304af1792ebf45cea72dabce2b577bc Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 24 Jan 2020 23:59:23 -0500 Subject: [PATCH 077/577] Update index.html --- index.html | 443 ++++++++++++++++++++++++----------------------------- 1 file changed, 197 insertions(+), 246 deletions(-) diff --git a/index.html b/index.html index d7a6bec1..6b608e23 100644 --- a/index.html +++ b/index.html @@ -9,7 +9,11 @@ -
    SnakeFall Redesign
    +
    SnakeFall Redesign
    +
    Solution
    @@ -18,443 +22,390 @@ - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + + - - - + + +
    SolutionNote
    Disabilities ActthejoshwolfeDisabilities Actthejoshwolfe
    Crashing DownthejoshwolfeCrashing Downthejoshwolfe
    Etch-a-sketchinukoblaincEtch-a-sketchinukoblainc
    Fruit FallXeroOlFruit FallXeroOl
    Block ValleyCreatorBlock ValleyCreator
    Block Valley 2CreatorBlock Valley 2Creator
    Spike MazeCreatorSpike MazeCreator
    Fruit MazeCreatorFruit MazeCreator
    Box BridgeCreatorBox BridgeCreator
    Please add animationsCreatorPlease add animationsCreator
    The OrdealCreatorThe OrdealCreator
    Coral BlockCreatorCoral BlockCreator
    AdventureCreatorAdventureCreator
    Sky GridCreatorSky GridCreator
    Block TrainCreatorBlock TrainCreator
    Turn AroundCreatorTurn AroundCreator
    Turn Around 2CreatorTurn Around 2Creator
    There and Back AgainCreatorThere and Back AgainCreator
    You Don't Have To Wait For AnimationsCreatorYou Don't Have To Wait For AnimationsCreator
    KeyholeCreatorKeyholeCreator
    Block Train 2CreatorBlock Train 2Creator
    Fruit Maze 2CreatorFruit Maze 2Creator
    Tight SpaceCreatorTight SpaceCreator
    Floating FruitsCreatorFloating FruitsCreator
    SkyscraperCreatorSkyscraperCreator
    Fruit Maze 3CreatorFruit Maze 3Creator
    Fruit Maze 4CreatorFruit Maze 4Creator
    Fruit Maze 5CreatorFruit Maze 5Creator
    Fruit Maze 6CreatorFruit Maze 6Creator
    DisarmCreatorDisarmCreator
    Level 1CreatorLevel 1Creator
    Level 2CreatorLevel 2Creator
    Bumpy RoadCreatorBumpy RoadCreator
    Level 0 "Checkmark Underpass"CreatorLevel 0 "Checkmark Underpass"Creator
    Level 1 "Hanging spikes"CreatorLevel 1 "Hanging spikes"Creator
    Level 2 "Trap Mine"CreatorLevel 2 "Trap Mine"Creator
    Level 3 "The Servant"CreatorLevel 3 "The Servant"Creator
    Level 4 "Greed that goes well"CreatorLevel 4 "Greed that goes well"Creator
    Level 5 "Collapse"CreatorLevel 5 "Collapse"Creator
    Level 6 "Decisions"CreatorLevel 6 "Decisions"Creator
    Level 1CreatorLevel 1Creator
    NameCreatorNameCreator
    Level 2CreatorLevel 2Creator
    Level 3CreatorLevel 3Creator
    Level 3 2CreatorLevel 3 2Creator
    Balancing ActCreatorBalancing ActCreator
    TempleCreatorTempleCreator
    BasilicaCreatorBasilicaCreator
    The BirdcageCreatorThe BirdcageCreator
    The Birds UncagedCreatorThe Birds UncagedCreator
    StrippedCreatorStrippedCreator
    SerpentineCreatorSerpentineCreator
    The SawmillCreatorThe SawmillCreator
    The HardmillCreatorThe HardmillCreator
    Mine RescueCreatorMine RescueCreator
    Plane CrashCreatorPlane CrashCreator
    Top ShelfCreatorTop ShelfCreator
    Top Shelf 2CreatorTop Shelf 2Creator
    PlinkoCreatorPlinkoCreator
    The Puppet MasterCreatorThe Puppet MasterCreator
    Rainbow BridgeCreatorRainbow BridgeCreator
    CastleCreatorCastleCreator
    PerchCreatorPerchCreator
    NameCreatorNameCreator
    - -# NoHatCoder Puzzles - -|Solution|Creator|Note| -|---|:---:|:---:| -|[Fruity Gap](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&9&14?*Q01002*K01*I01*301*104*Q0/s2?46&60&74&75/s0?48&62&61/f0?49/#replay=nmGTi8PB&2rur0l2ullul0uululullurr2luu*0r0rrrdrr2*2r0uluurrdllu*1r2rddl0ddl)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| -|[Bridge](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&16&24?*v0*51*z0*V04*h0111*40*51*00111*40*51*00111*40*51*00111*40*51*0011122*0022*51*k0/b0?160&136&112/b1?161&137&113/b2?186&185&184/s1?206&205/b3?210&209&208/#replay=nmGTi8PB&1rru*0rdlululurdrdlululurdrdlululurdrdlulullurrdrdlulllurrrdllullurrdllullurrdlulllurrrd*4lu)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| -|[Abyss](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&19&12?*M0*41*m0*01201*50201*D04*90100011*D011*H01*70111*R0/s2?77&76/s0?65&64/f0?115/#replay=nmGTi8PB&2r0rrd2rrrdllur0r2rr0rrul2u*0l0u*2ldrr2lulldlddrdrru0ulll2lluluuuruul)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| -|[Tube](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&13&16?*U0*81*001*30*01*001*5011*001*301011*00*51011*001*601*001*2011001*001011*00*01*0040*61*U0/f0?67/s2?71&72&73&74/s0?87&88&89/s1?152&151&150/f1?153/#replay=nmGTi8PB&*0lu1uu*0rdl2u*0rddd*4l0*2rurrddd*2l1ulllddl2urrurrd*0lurrr1uul2dr1lldluru*0r2u1dd2u*0ldd1r2l0ll1u0*0lddl1u*0lddl)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| -|[Tunnel](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&26?*o0*E1*J0111*J0111*J0111*J0111*I0*01*I0*01*I0*01*I0*01*I0*01*I0*01*504*M01*30101*J0*31*t0/s0?300&299&298&297/f0?309/s2?326&325&324&323/b0?352/#replay=nmGTi8PB&2rdrrrulldl0ulld*1rdllulllurrr2ll0drrurrrurrrulllurrdlll2ll0ll2l0llullldrr2u0r2rrdllluuu0*0uru2ll0lldrd*3l2uu*5l0*1ld2l)|[NoHatCoder](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| -|[Transport](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&20&28?*s01*F0111*101*F0101*101*A0*2101*101*A011011101*101*A01*201*101*A010011101*101*A011011101*101*D011101*101*D011101*101*D011101*101*C0*0101*10*51*22*2101*L01004*K0101*L0101*M02*u0/b0?232/b1?260/s2?288&287/s0?316&315&314&313/s1?344&343&342&341&340/#replay=nmGTi8PB&rrdll1r0l1urr*0ulldd2r1drr2ul0ll2lu*1ld*0rullurururrr1rrr2rr0urruurr2r0r2r0r2r0ru*0lurr2ululur0rr2rurrr0urru*0lurr1u0uru*3l1*4lu*4r0u*3r1rur2u1uu2l1l0r1lld0ur1rr0uu1ulldrdr2u1ur2*1rurr0ulu*1rdddrr1*0ulu*1r*0drr)|[edderiofer, NoHatCoder, & Gooby](http://nohatcoder.dk/snakebird.htm#Alb_rnwk4mQvImxf_EsEmElEic-E25E0iNuCV4MnE-oswHlCcgWuF_oH0gWetFdcwAkqE8EgpcoVRsizGqQmiqL8EEwec4mY_66dD1jD2EC07wkgME41YkD_OFwdAlOf-qXvhV8bnhkI3EkGo-LkFG-bzG0MlMOviElIEupO458oWpAU0qEsMMR4wUOyuEBC1gzlR2I_5Mt5A0HSulgH1ooWx_Es4loHcN43EHuNdK_qchlGP1JfNM3Ms5Mkoywc0im4VuSkyM14)| - -# Avis Anguis Puzzles - -|Solution|Creator|Note| -|---|:---:|:---:| -|[Demo](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&27&49?*z0*z0*z0*z0*C0*32*b02*31*Z05002*21*d04001*S0*71*101*R015*61*1011*Q010*61*201*S0*51*3011*Y011*401*R01*201*501*R01*201*501*R0101*001*4011*C0*2100*410110111*401*F0*0100*71*801*H011222*61*801*R0*01*90111*Q0111*h011*h011*h011*z0*t0/b0?800&801/b1?657&660&709&758&807/b2?415&414&317&268/s2?809&810&761&712&663/s1?793&792/s0?751&752/f1?270/f0?368/#replay=nmGTi8PB&urrd*3l1*6r0uru*1rurru1u0r2llulluu*0lddruuru0uullluld*1lul2uldddllu*0lu*0rdrr1l2ul1ll2luuu1l2rrru*2ld1ur2r1r2ruruuuruuur1*3r2u*0r1ululur2rr1rr2ru1u*0rdrrr2u*0rddrrr0d*2r)|Terzalo| -|[Level A](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&14&12?11*30*11*401110004*10111*6011*6011*6011*001*1011*6011*50111*50111*6011*6011*50111*5011/b0?52&63&62&74&86&98&110&122&134&135&136&137&138&139&140&128&117&92&91&68&67&54/s2?76&64&65&66/f0?101/s1?124&123/#replay=nmGTi8PB&2drruullu1rurrururr2ldluu*0rururruuru1ulll2uu*2luu1luluul)|Connorses| -|[Level B](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&14&13?*D04*4011*7011*50*11*40*41*10*61*00111*60111*001100*11*40*11*50*01*0011100*6100*61000111/f0?30/s1?133&132&145&146/s0?136&137/#replay=nmGTi8PB&1r0l1uuruurrruullulluu*0rdd*0ldddru0u1u0rrr1rrruu0u1u0l1rrullull0ll1ull0luu1uuu)|Connorses| -|[Level 1](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&10&5?*a04414400100/f0?7/s2?26/s1?31&32/s0?38&37&36/#replay=nmGTi8PB&1ur2r1r2r0ul1ul2l0uu1u2uld1ld0ld)|CHz| -|[Level 2](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&8&7?*9041110111*A01110*D1/s0?9&8&7/s1?11&12/f1?33/f0?29/#replay=nmGTi8PB&1lu0rddllldrru*0rdll1lu0l1ru0uu1rrr0urrr)|CHz| -|[Level 3](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&12&14?*l01*901*901*9010011*50*11*B01*101*104*010*910*51/s1?47&46&45&44/b0?102&74&58&59&60&61&62/b1?132&118&104&90&76&75&131&129&128&114&100&86&72&73/s0?89&103&117&116/s2?94&95/#replay=nmGTi8PB&llddru1u*0lddrrulluruu*3r2ururu1rddr2l1uul2lu*4ldrr0rullu2dr0uruuulluu*5rulul1urruuulu*5lddrrd2u1dluuruul2llur1ur2u1u2l1l0ldl2u0l2r0uruu*2ldd2u0ruu2*0ru0rulluruu*2rddluuu1uurddrrur2*1r1*2r0rd*1r)|CHz| - -# GameBoy Puzzles - -|Solution|Creator|Note| -|---|:---:|:---:| -|[Level 1](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&16&20?*e0*010*01*70*010*01*504*l01*E02*Y0*21*A0*21*g0*61*90*11*B0*11*40/f0?68/f1?94/f2?222/s1?226&225&224/s2?248&247&246&245/#replay=nmGTi8PB&1*1r2urrruuu*0ruuulullddd*6lu*5r1ulluluu2u1r2uuuru1rurul2ururuuu1*7l2u*2ldddrrr*0uruurur*0u*5l1d2lllddd)|freeball1|| -|[Level 2](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&20?*z0*B0*11*0011*00*61*0011*00*11*5011*E011*E011*E011*204*7011*E011*P0*11*0011*00*61*0011*00*11*5011*E011*E011*50/f0?128/f1?131/f2?246/f3?253/s0?22&42&62/s5?76&77&57&37/#replay=nmGTi8PB&5*1ld*0lul*0u0*2r5r0u*0l5ullurrd*5ru*5l0llu*0rur5*0lu0rd*0rd*5ruuu5*Aruuu)|freeball1|| -|[Level 3](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&19&20?*z0*Y02002002002*N0*C1*00*C1*00*01*C0*0104*A0*01*C0*01*C0*01*C0*010202020202020202*01*C0*01*C0*01*C0*01*C0/b0?83&63&62&82/s0?21&22&23&24/s3?41&42/#replay=nmGTi8PB&3drrru0ldrruluruuurrrdd*2ruuld*1luulllddr3rrru0rruurrrdd*3ruuld*2luullldd3rrru0rrruu*4r3*1r0rrulu3rrrd*7lulld0l)|freeball1|| -|[Level 4](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&16&21?*z0*G01*404*V022*G02*E0*01*J0*51*301000*51*m0*01*C0*01*T0/s2?178&179&180&181&182/s3?118&139&160/f0?151/f1?264/#replay=nmGTi8PB&2lldlddd*0rullull3*2ldldrru*1rdllu*0luur2llluuullluurr3urrulld*1l2*0ulllurrr*0dlddrr3dluururruuururr*0u2*0rurr*0u)|freeball1|| -|[Level 5](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&20?*u011101*00102*401410001*1020100*0101110*01*5011*10*51001011*801*1011*D0111*501101000*0101*301*10*11*00100011*40111*10*01001*1011*001*301001001101*B0111*801*101110011000*1100*K1/s1?43&42&41/s2?23&22&21/b0?24&44&45&25/f0?123/#replay=nmGTi8PB&2u*1r1*3rddrrruu*0rull2drrrdrruurr1lurururuu*4lulluu*3rddlddrurruurulll2rdrrdlllullddlu*2ruuruu*1l1luullluu*1l2ldd*2l1u2uu*1lddrdr1l2uu1luulurrr2rrulldluluurru1urullulluuurrrddllulurruluuul2*0rurr1lu*0ruuluur2ullulu1ulll2urrruruu*3rururuu*4lulllulldd*0luu1luuu)|freeball1|| -|[Level 6](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&20?*b0*D1000*D1*z0*z0*w04*z0*K0/s2?123&103/s0?135&115/f0?155/f1?175/f2?143/f3?163/f4?185/f5?187/f6?190/f7?193/#replay=nmGTi8PB&2d*8rull0lll2*0l0lll2lll0*0l2lll0llur2urrr0rrr2rrr0rrr2ru*0ld0u*1l2luurr0urrr2rruurrr0dluruu*1r2uluul0ulllurrddruuluull2d)|freeball1|| -|[Level 7](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&20?00*C1*201*001104001*9011*s011101*8010011*001*9011001*60100021120001*401110*010111*R01*101*901*F01*c0111*h0/f0?27/s3?147&167&166&165/s1?152&172&173/b0?90&89&69&70/f1?272/f2?239/#replay=nmGTi8PB&1ulur3llurrdd*1ruuurruuuru*4l*0ulldddrruuulu*4r*0dlldddlldddrrr1drrull3ulll1llldrr3l1rurrruuulluurruuurrdddrrru*0lurrrd*0luuulluurruuurullluuu3luuur*0urruuurullluuu)|freeball1|| -|[Level 8](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&20?*z0*004*N0202*j01*2011*60111*D01110*01*80111*3011*O0111*X0111*X0111*80*91*00/s1?304&324/s0?305&325/f0?291/f1?247/f2?171/f3?179/f4?98/#replay=nmGTi8PB&rru*0ruru*1l1rrr0uuuluru*2rdll1u*0ru0u1*0l0*0lu1u0u1*0r0*0ru1u0u1u*4ruluuulur*0u*3lddr*0dluu0u1uu0rulluluuu1ruluu*0luu*0ruuurulluluuu)|freeball1|| -|[Level 9](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&20?*S011*E011*z00*21*4011*00*21*4011*H011*E011*a01*30202202000*0104*102*002000*01*10*61*60*61*Q0*61*10/s2?61&81&101/s0?63&83&103/f0?128/f1?132/f2?17/f3?332/#replay=nmGTi8PB&*2r2*1ru*2r0u*3rddllluu2rrulldrrrur0rurruu2u0r2rrruuululuuu0uu2ul*0dllddrddd*7luuurruurrddrrruurrddrruuruuu0luu*0l2urululu*3ldddrrruu*0l0*2lul2lulldddruu0u*0l2u*0ld)|freeball1|| -|[Level 10](https://jmdiamond3.github.io/Snakefall-Redesign/framework.html#level=HyRr4JK1&18&21?*m01*c0*11*1011*50*110200011*B0*01*402*11000*0100222*00*11*O011*B01120111*202*301100111*202*3011*504*5011*B0*21*B0*21*B01*00111*901*00111/f0?58/f1?129/s1?285&286&287/s0?264&265&266&267&268/f2?183/#replay=nmGTi8PB&urrr1urrruu0*0u*1luuu*1rur*2dl1rul0l*1u1u*1lur0rrrullluu*5l1ull0lulu*0rurr1urrdllurrru*0r0*1r*2dlllururr1*0rdddllld*0l0rru*5l)|freeball1|| - --------------------------------------- - -# Experimental Snakebird Puzzles - -|Solution|Creator|Note| -|---|:---:|:---:| -|Under Cover|[XeroOl](https://github.com/XeroOl)| -|Snake Filter|[XeroOl](https://github.com/XeroOl)| -|Platformway to Heaven|[thejoshwolfe](https://github.com/thejoshwolfe)| -|Under Cover 2|[XeroOl](https://github.com/XeroOl)| -|Low Clearance|[XeroOl](https://github.com/XeroOl)| -|Baited Trap|[XeroOl](https://github.com/XeroOl)| -|Gateway to Freedom|[LevelWorld](https://github.com/Fargogoosey)| -|House on Fire|[Gooby](https://github.com/jmdiamond3)| -|Underground|[Gooby](https://github.com/jmdiamond3)| From 1291dfbc49d95a466394b4c8bafec36538b01fa2 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 25 Jan 2020 00:18:55 -0500 Subject: [PATCH 078/577] Update format.css --- format.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/format.css b/format.css index 42783186..df05630d 100644 --- a/format.css +++ b/format.css @@ -1,5 +1,5 @@ body{ - font-family: Palatino; + font-family: Optima; } table{ From 3d5f9df0f52724755b1763ad9c25b50e5ac1a8de Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 25 Jan 2020 00:19:27 -0500 Subject: [PATCH 079/577] Update index.html --- index.html | 170 +++++++++++++++++++++++++++-------------------------- 1 file changed, 88 insertions(+), 82 deletions(-) diff --git a/index.html b/index.html index 6b608e23..7f8e971b 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ Snakefall - + @@ -48,361 +48,367 @@ Block Valley - Creator + XeroOl Block Valley 2 - Creator + XeroOl Spike Maze - Creator + XeroOl Fruit Maze - Creator + XeroOl Box Bridge - Creator + XeroOl Please add animations - Creator + XeroOl The Ordeal - Creator + XeroOl Coral Block - Creator + XeroOl Adventure - Creator + XeroOl Sky Grid - Creator + XeroOl Block Train - Creator + XeroOl Turn Around - Creator + XeroOl Turn Around 2 - Creator + XeroOl - There and Back Again - Creator + There and Back Again + XeroOl You Don't Have To Wait For Animations - Creator + XeroOl Keyhole - Creator + XeroOl Block Train 2 - Creator + XeroOl Fruit Maze 2 - Creator + XeroOl Tight Space - Creator + XeroOl Floating Fruits - Creator + XeroOl Skyscraper - Creator + XeroOl Fruit Maze 3 - Creator + XeroOl - - Fruit Maze 4 - Creator + + Fruit Maze 4 + XeroOl - - Fruit Maze 5 - Creator + + Fruit Maze 5 + XeroOl - - Fruit Maze 6 - Creator + + Fruit Maze 6 + XeroOl - - Disarm - Creator + + Disarm + XeroOl Level 1 - Creator + XeroOl Level 2 - Creator + XeroOl Bumpy Road - Creator + XeroOl Level 0 "Checkmark Underpass" - Creator + XeroOl Level 1 "Hanging spikes" - Creator + XeroOl Level 2 "Trap Mine" - Creator + XeroOl Level 3 "The Servant" - Creator + XeroOl Level 4 "Greed that goes well" - Creator + XeroOl Level 5 "Collapse" - Creator + XeroOl Level 6 "Decisions" - Creator + XeroOl Level 1 - Creator + XeroOl Name - Creator + XeroOl Level 2 - Creator + XeroOl Level 3 - Creator + XeroOl Level 3 2 - Creator - + XeroOl + Derived from Cookie's level above Balancing Act - Creator + XeroOl - - Temple - Creator + + Temple + XeroOl + + + Renovated Temple + XeroOl + Addresses a common criticism of Temple + Basilica - Creator - + Gooby + Based on Joel's levels above The Birdcage - Creator + Gooby The Birds Uncaged - Creator - + XeroOl + Derived from Gooby's level above Stripped - Creator - + Gooby + Based on The Birdcage and The Birds Uncaged Serpentine - Creator + Gooby The Sawmill - Creator + Gooby The Hardmill - Creator - + Joel + Derived from Gooby's level above Mine Rescue - Creator - + Gooby + Allow time for solution to load Plane Crash - Creator - + Gooby + I'm sorry Top Shelf - Creator - + Gooby + Novelty Guess-the-Exit Special Top Shelf 2 - Creator + Gooby Plinko - Creator + Gooby The Puppet Master - Creator + Gooby Rainbow Bridge - Creator + Gooby Castle - Creator + Gooby - - Perch - Creator + + Perch + Gooby Name - Creator + From 588929e25780afba62e9cc30b6dfa47ebdfdff8b Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 25 Jan 2020 00:20:46 -0500 Subject: [PATCH 080/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 7f8e971b..59e319a4 100644 --- a/index.html +++ b/index.html @@ -1,7 +1,7 @@ Snakefall - + From c300c476511bb0b75f7debbedaef9f0890faadd5 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 25 Jan 2020 00:28:50 -0500 Subject: [PATCH 081/577] Update index.html --- index.html | 74 ++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 13 deletions(-) diff --git a/index.html b/index.html index 59e319a4..d6a524c6 100644 --- a/index.html +++ b/index.html @@ -268,32 +268,26 @@ - - Name + + Level 2 XeroOl - Level 2 + Level 3 XeroOl - Level 3 - XeroOl - - - - - Level 3 2 + Level 3 2 XeroOl Derived from Cookie's level above - - Balancing Act + + Balancing Act XeroOl @@ -305,7 +299,7 @@ - Renovated Temple + Renovated Temple XeroOl Addresses a common criticism of Temple @@ -415,3 +409,57 @@ + + -
    +
    Show Hidden Options
    Most checkmarks contain links to solutions, though some are not accessible without a password.
    +
    Standard Puzzles
    @@ -331,7 +333,7 @@ - + @@ -352,7 +354,7 @@ - + @@ -373,7 +375,7 @@ - + @@ -401,7 +403,7 @@ - + @@ -477,8 +479,8 @@
    Level 3 2 Joel Fox Derived from Cookie's level above
    Renovated Temple Joel Fox Addresses a common criticism of Temple
    The Birds Uncaged Joel Fox Derived from Gooby's level above
    The Hardmill Joel Fox Derived from Gooby's level above
    -
    +
    + +
    +
    + + + +
    +
    Demo Level Snakefall Redesign Github @@ -676,7 +682,7 @@ document.getElementById("passWindow").style.visibility = "visible"; }); function validatePass(){ - if(document.getElementById('pass').value == "password1"){ + if(document.getElementById('passInput').value == "password1"){ var x = document.getElementsByClassName("hiddenItem"); var i; for (i = 0; i < x.length; i++) { @@ -684,6 +690,7 @@ x[i].style.pointerEvents = "auto"; x[i].style.cursor = "pointer"; } + document.getElementById("passWindow").style.visibility = "hidden"; return true; } else alert("Incorrect Password"); From 4ff5a97cdc3434d1d9617dbd3985c1b09a8aceb0 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 25 Jan 2020 19:41:17 -0500 Subject: [PATCH 111/577] Update format.css --- format.css | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/format.css b/format.css index 4a9d0de6..715ee654 100644 --- a/format.css +++ b/format.css @@ -177,10 +177,18 @@ td a{ #passWindow{ width: 300px; height: 300px; - background-color: blue; + background-color: rgba(0,0,0,.8); position: absolute; - left: 50%; - margin-left: -50px; - top: 50%; - margin-top: -50px; + left: 0; + margin-left: auto; + right: 0; + margin-right: auto; + color: white; + display: inline-block; + visibility: hidden; +} + +form{ + display: inline-block; + } From 15f2ceec2e01df674c247dc37f0fd071ac20a37a Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 25 Jan 2020 19:50:37 -0500 Subject: [PATCH 112/577] Update index.html --- index.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 765e348e..769212d0 100644 --- a/index.html +++ b/index.html @@ -684,12 +684,16 @@ function validatePass(){ if(document.getElementById('passInput').value == "password1"){ var x = document.getElementsByClassName("hiddenItem"); - var i; - for (i = 0; i < x.length; i++) { + for (var i = 0; i < x.length; i++) { x[i].style.filter = "blur(0)"; x[i].style.pointerEvents = "auto"; x[i].style.cursor = "pointer"; } + var y = document.getElementsByClassName("disabled"); + for (var i = 0; i < y.length; i++) { + y[i].style.pointerEvents = "auto"; + y[i].style.cursor = "pointer"; + } document.getElementById("passWindow").style.visibility = "hidden"; return true; } From 5be9670cf9783be6f4f3b3772009df67d11dd66c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 25 Jan 2020 20:12:41 -0500 Subject: [PATCH 113/577] Update index.html --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 769212d0..69a44f38 100644 --- a/index.html +++ b/index.html @@ -12,9 +12,9 @@
    Snakefall Redesign
    - - - +
    +
    +
    From 17e3bd1af0f54db59ef7b50870380092b99e0134 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 25 Jan 2020 20:12:58 -0500 Subject: [PATCH 114/577] Update format.css --- format.css | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/format.css b/format.css index 715ee654..142807a1 100644 --- a/format.css +++ b/format.css @@ -175,20 +175,23 @@ td a{ } #passWindow{ + height: 100px; width: 300px; - height: 300px; + margin: 0 auto; background-color: rgba(0,0,0,.8); position: absolute; left: 0; - margin-left: auto; right: 0; - margin-right: auto; color: white; display: inline-block; visibility: hidden; + border: 10px solid black; + border-radius: 10px; } form{ - display: inline-block; - + width:50%; + margin: 0 auto; + text-align: center; + padding: 10px; } From 611a69e60f99c8470f65ccfa39d962783253573e Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 25 Jan 2020 22:23:43 -0500 Subject: [PATCH 115/577] Update framework.html --- framework.html | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) diff --git a/framework.html b/framework.html index 2f81f0f2..be5563e4 100644 --- a/framework.html +++ b/framework.html @@ -1,4 +1,86 @@ + + Snakefall + + + + + + + + +
    + +
    +
    + Controls (hover for hotkeys): +
    + Arrows/WASD to move + + +
    + + Moves: 0+0 + + + +
    + + + + +
    This project on Github: thejoshwolfe/snakefall version ???
    +
    Check out some community made levels, and share your levels there!
    + +
    This game is a clone of Snakebird by Noumenon Games.
    + + + + + + +
    Snakefall Redesign
    + +
    Show Hidden Options
    Most checkmarks contain links to solutions, though some are not accessible without a password.
    +
    + +
    Standard Puzzles
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SolutionLevelCreatorNote
    Disabilities Actthejoshwolfe
    Crashing Downthejoshwolfe
    Etch-a-sketchinukoblainc
    Fruit FallXeroOl
    Block ValleyXeroOl
    Block Valley 2XeroOl
    Spike MazeXeroOl
    Fruit MazeXeroOl
    Box BridgeXeroOl
    Please add animationsXeroOl
    The Ordealthejoshwolfe
    Coral BlockXeroOl
    AdventureXeroOl
    Sky GridXeroOl
    Block TrainXeroOl
    Turn AroundXeroOl
    Turn Around 2XeroOl
    There and Back Againgavinksong
    You Don't Have To Wait For Animationsthejoshwolfe
    KeyholeXeroOl
    Block Train 2XeroOl
    Fruit Maze 2XeroOl
    Tight SpaceXeroOl
    Floating FruitsXeroOl
    SkyscraperXeroOl
    Fruit Maze 3XeroOl
    Fruit Maze 4XeroOl
    Fruit Maze 5XeroOl
    Fruit Maze 6XeroOl
    DisarmXeroOl
    Level 1DoctorEndugu
    Level 2DoctorEndugu
    Bumpy RoadXeroOl
    Level 0 "Checkmark Underpass"Teal Knight
    Level 1 "Hanging spikes"Teal Knight
    Level 2 "Trap Mine"Teal Knight
    Level 3 "The Servant"Teal Knight
    Level 4 "Greed that goes well"Teal Knight
    Level 5 "Collapse"Teal Knight
    Level 6 "Decisions"Teal Knight
    Level 1Cookie
    Level 2Cookie
    Level 3Cookie
    Level 3 2Joel FoxDerived from Cookie's level above
    Balancing ActIHNN
    TempleJoel Fox
    Renovated TempleJoel FoxAddresses a common criticism of Temple
    BasilicaGoobyBased on Joel's levels above
    The BirdcageGooby
    The Birds UncagedJoel FoxDerived from Gooby's level above
    StrippedGoobyBased on The Birdcage and The Birds Uncaged
    SerpentineCollaborationCreated by Gooby & Joel Fox
    The SawmillGooby
    The HardmillJoel FoxDerived from Gooby's level above
    Mine RescueGoobyAllow time for solution to load
    Fruit TempleXeroI0I'm sorry
    Plane CrashGoobyNovelty Guess-the-Exit Special
    Top ShelfGooby
    Top Shelf 2Gooby
    PlinkoGooby
    The Puppet MasterGooby
    Rainbow BridgeGooby
    CastleGooby
    PerchGooby
    Black MambaGooby
    +
    +
    + +
    nohatcoder Puzzles
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SolutionLevelCreatorNote
    Fruity Gapnohatcoder
    Bridgenohatcoder
    Abyssnohatcoder
    Tubenohatcoder
    Tunnelnohatcoder
    Transportedderiofer, nohatcoder, & Gooby
    +
    +
    + +
    Avis Anguis Puzzles
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SolutionLevelCreatorNote
    DemoTerzalo
    Level AConnorses
    Level BConnorses
    Level 1CHz
    Level 2CHz
    Level 3CHz
    +
    +
    + +
    Gameboy Puzzles
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SolutionLevelCreatorNote
    Level 1freeball1
    Level 2freeball1
    Level 3freeball1
    Level 4freeball1
    Level 5freeball1
    Level 6freeball1
    Level 7freeball1
    Level 8freeball1
    Level 9freeball1
    Level 10freeball1
    +
    + + - -
    Snakefall Redesign
    Show Hidden Options
    Most checkmarks contain links to solutions, though some are not accessible without a password.
    @@ -40,456 +40,456 @@ - - Disabilities Act + + Disabilities Act thejoshwolfe - - Crashing Down + + Crashing Down thejoshwolfe - - Etch-a-sketch + + Etch-a-sketch inukoblainc - - Fruit Fall + + Fruit Fall XeroOl - - Block Valley + + Block Valley XeroOl - - Block Valley 2 + + Block Valley 2 XeroOl - - Spike Maze + + Spike Maze XeroOl - - Fruit Maze + + Fruit Maze XeroOl - - Box Bridge + + Box Bridge XeroOl - - Please add animations + + Please add animations XeroOl - - The Ordeal + + The Ordeal thejoshwolfe - - Coral Block + + Coral Block XeroOl - - Adventure + + Adventure XeroOl - - Sky Grid + + Sky Grid XeroOl - - Block Train + + Block Train XeroOl - - Turn Around + + Turn Around XeroOl - - Turn Around 2 + + Turn Around 2 XeroOl - - There and Back Again + + There and Back Again gavinksong - - You Don't Have To Wait For Animations + + You Don't Have To Wait For Animations thejoshwolfe - - Keyhole + + Keyhole XeroOl - - Block Train 2 + + Block Train 2 XeroOl - - Fruit Maze 2 + + Fruit Maze 2 XeroOl - - Tight Space + + Tight Space XeroOl - - Floating Fruits + + Floating Fruits XeroOl - - Skyscraper + + Skyscraper XeroOl - - Fruit Maze 3 + + Fruit Maze 3 XeroOl - Fruit Maze 4 + Fruit Maze 4 XeroOl - Fruit Maze 5 + Fruit Maze 5 XeroOl - Fruit Maze 6 + Fruit Maze 6 XeroOl - Disarm + Disarm XeroOl - - Level 1 + + Level 1 DoctorEndugu - - Level 2 + + Level 2 DoctorEndugu - - Bumpy Road + + Bumpy Road XeroOl - - Level 0 "Checkmark Underpass" + + Level 0 "Checkmark Underpass" Teal Knight - - Level 1 "Hanging spikes" + + Level 1 "Hanging spikes" Teal Knight - - Level 2 "Trap Mine" + + Level 2 "Trap Mine" Teal Knight - - Level 3 "The Servant" + + Level 3 "The Servant" Teal Knight - - Level 4 "Greed that goes well" + + Level 4 "Greed that goes well" Teal Knight - - Level 5 "Collapse" + + Level 5 "Collapse" Teal Knight - - Level 6 "Decisions" + + Level 6 "Decisions" Teal Knight - - Level 1 + + Level 1 Cookie - - Level 2 + + Level 2 Cookie - - Level 3 + + Level 3 Cookie - - Level 3 2 + + Level 3 2 Joel Fox Derived from Cookie's level above - - Balancing Act + + Balancing Act IHNN - Temple + Temple Joel Fox - - Renovated Temple + + Renovated Temple Joel Fox Addresses a common criticism of Temple - - Basilica + + Basilica Gooby Based on Joel's levels above - - The Birdcage + + The Birdcage Gooby - - The Birds Uncaged + + The Birds Uncaged Joel Fox Derived from Gooby's level above - - Stripped + + Stripped Gooby Based on The Birdcage and The Birds Uncaged - Serpentine + Serpentine Collaboration Created by Gooby & Joel Fox - - The Sawmill + + The Sawmill Gooby - - The Hardmill + + The Hardmill Joel Fox Derived from Gooby's level above - - Mine Rescue + + Mine Rescue Gooby Allow time for solution to load - Fruit Temple + Fruit Temple XeroI0 I'm sorry - - Plane Crash + + Plane Crash Gooby Novelty Guess-the-Exit Special - - Top Shelf + + Top Shelf Gooby - - Top Shelf 2 + + Top Shelf 2 Gooby - - Plinko + + Plinko Gooby - - The Puppet Master + + The Puppet Master Gooby - - Rainbow Bridge + + Rainbow Bridge Gooby - - Castle + + Castle Gooby - - Perch + + Perch Gooby - - Black Mamba + + Black Mamba Gooby @@ -508,42 +508,42 @@ - Under Cover + Under Cover XeroOl - Snake Filter + Snake Filter XeroOl - Platformway to Heaven + Platformway to Heaven thejoshwolfe - Under Cover 2 + Under Cover 2 XeroOl - Low Clearance + Low Clearance XeroOl - Baited Trap + Baited Trap XeroOl @@ -557,7 +557,7 @@ - House on Fire + House on Fire Gooby @@ -589,43 +589,43 @@ - - Fruity Gap + + Fruity Gap nohatcoder - - Bridge + + Bridge nohatcoder - - Abyss + + Abyss nohatcoder - - Tube + + Tube nohatcoder - - Tunnel + + Tunnel nohatcoder - - Transport + + Transport edderiofer, nohatcoder, & Gooby @@ -643,43 +643,43 @@ - - Demo + + Demo Terzalo - - Level A + + Level A Connorses - - Level B + + Level B Connorses - - Level 1 + + Level 1 CHz - - Level 2 + + Level 2 CHz - - Level 3 + + Level 3 CHz @@ -697,71 +697,71 @@ - - Level 1 + + Level 1 freeball1 - - Level 2 + + Level 2 freeball1 - - Level 3 + + Level 3 freeball1 - - Level 4 + + Level 4 freeball1 - - Level 5 + + Level 5 freeball1 - - Level 6 + + Level 6 freeball1 - - Level 7 + + Level 7 freeball1 - - Level 8 + + Level 8 freeball1 - - Level 9 + + Level 9 freeball1 - - Level 10 + + Level 10 freeball1 From de1e846e721d3016e572b9094831096042453950 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 18:23:11 -0500 Subject: [PATCH 168/577] Rename framework.html to Framework.html --- framework.html => Framework.html | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename framework.html => Framework.html (100%) diff --git a/framework.html b/Framework.html similarity index 100% rename from framework.html rename to Framework.html From bed50320db163dc55e5c35ac4b3cdc94b261f155 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 18:23:14 -0500 Subject: [PATCH 169/577] Rename format.css to Format.css --- format.css => Format.css | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename format.css => Format.css (100%) diff --git a/format.css b/Format.css similarity index 100% rename from format.css rename to Format.css From 7839d83db9ea5d223b63e0011aa3dacd168560fe Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 18:26:28 -0500 Subject: [PATCH 170/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index cd98a96d..3faa5161 100644 --- a/index.html +++ b/index.html @@ -571,7 +571,7 @@ - Bundók + Bundók Gooby From 605cfd5cff89050a4983b8ded17b8b17b4014c52 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 18:27:12 -0500 Subject: [PATCH 171/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 3faa5161..37d4fdb2 100644 --- a/index.html +++ b/index.html @@ -564,7 +564,7 @@ - Underground + Underground Gooby From bb7d8b44ea7156dfbab3d40fc51eb594b7f0260b Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 18:33:23 -0500 Subject: [PATCH 172/577] Update index.html --- index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.html b/index.html index 37d4fdb2..7494ecd8 100644 --- a/index.html +++ b/index.html @@ -564,14 +564,14 @@ - Underground + Underground Gooby - Bundók + Bundók Gooby From ade4ec6052233fd859e5e4c0aba7d9479cbfe835 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 22:57:16 -0500 Subject: [PATCH 173/577] Update Experimental.js --- Experimental.js | 87 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 29 deletions(-) diff --git a/Experimental.js b/Experimental.js index 98f9be43..a49dcea7 100644 --- a/Experimental.js +++ b/Experimental.js @@ -31,7 +31,7 @@ var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM]; //Gooby var SNAKE = "s"; var BLOCK = "b"; var FRUIT = "f"; -var JELLY = "j"; +var CLOUD = "j"; var tileSize = 34; var level; @@ -147,7 +147,7 @@ function parseLevel(string) { if (object.type === SNAKE) locationsLimit = -1; else if (object.type === BLOCK) locationsLimit = -1; else if (object.type === FRUIT) locationsLimit = 1; - else if (object.type === JELLY) locationsLimit = -1; + else if (object.type === CLOUD) locationsLimit = -1; else throw parserError("expected object type code"); cursor += 1; @@ -501,7 +501,7 @@ document.addEventListener("keydown", function(event) { if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } return; case "J".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(JELLY); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } return; case "D".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } @@ -659,7 +659,7 @@ var paintButtonIdAndTileCodes = [ ["paintPlatformButton", PLATFORM], ["paintSnakeButton", SNAKE], ["paintBlockButton", BLOCK], - ["paintJellyButton", JELLY], + ["paintCloudButton", CLOUD], ]; paintButtonIdAndTileCodes.forEach(function(pair) { var id = pair[0]; @@ -765,8 +765,8 @@ canvas.addEventListener("dblclick", function(event) { } else if (object.type === FRUIT) { // edit fruits, i guess paintBrushTileCode = FRUIT; - } else if (object.type === JELLY) { - paintBrushTileCode = JELLY; + } else if (object.type === CLOUD) { + paintBrushTileCode = CLOUD; } else throw unreachable(); paintBrushTileCodeChanged(); } @@ -1110,14 +1110,14 @@ function newFruit(location) { locations: [location], }; } -function newDirt(location) { - var jellys = getObjectsOfType(JELLY); - jellys.sort(compareId); - for (var i = 0; i < jellys.length; i++) { - if (jellys[i].id !== i) break; +function newCloud(location) { + var clouds = getObjectsOfType(CLOUD); + clouds.sort(compareId); + for (var i = 0; i < clouds.length; i++) { + if (clouds[i].id !== i) break; } return { - type: JELLY, + type: CLOUD, id: i, dead: false, // unused locations: [location], @@ -1152,8 +1152,8 @@ function paintAtLocation(location, changeLog) { object.id = newBlock().id; } else if (object.type === FRUIT) { object.id = newFruit().id; - } else if (object.type === JELLY) { - object.id = newDirt().id; + } else if (object.type === CLOUD) { + object.id = newCloud().id; } else throw unreachable(); level.objects.push(object); changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); @@ -1230,10 +1230,10 @@ function paintAtLocation(location, changeLog) { var object = newFruit(location) level.objects.push(object); changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); - } else if (paintBrushTileCode === JELLY) { + } else if (paintBrushTileCode === CLOUD) { paintTileAtLocation(location, SPACE, changeLog); removeAnyObjectAtLocation(location, changeLog); - var object1 = newDirt(location) + var object1 = newCloud(location) level.objects.push(object1); changeLog.push([object1.type, object1.id, serializeObjectState(null), serializeObjectState(object1)]); } else throw unreachable(); @@ -1333,7 +1333,7 @@ function reduceChangeLog(changeLog) { changeLog.splice(i, 1); i--; } - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === JELLY) { + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === CLOUD) { for (var j = i + 1; j < changeLog.length; j++) { var otherChange = changeLog[j]; if (otherChange[0] === change[0] && otherChange[1] === change[1]) { @@ -1457,7 +1457,7 @@ function undoChanges(changes, changeLog) { if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; paintTileAtLocation(location, fromTileCode, changeLog); - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === JELLY) { + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === CLOUD) { // change object var type = change[0]; var id = change[1]; @@ -1534,8 +1534,8 @@ function describe(arg1, arg2) { if (arg1 === FRUIT) { return "Fruit"; } - if (arg1 === JELLY) { - return "Dirt"; + if (arg1 === CLOUD) { + return "Cloud"; } if (typeof arg1 === "object") return describe(arg1.type, arg1.id); throw unreachable(); @@ -1747,7 +1747,7 @@ function move(dr, dc) { // eat removeObject(otherObject, changeLog); ate = true; - } else if (otherObject.type === JELLY) { + } else if (otherObject.type === CLOUD) { removeObject(otherObject, changeLog); } else { // push objects @@ -1844,7 +1844,7 @@ function move(dr, dc) { var dyingObjects = []; var fallingObjects = level.objects.filter(function(object) { if (object.type === FRUIT) return; // can't fall - if (object.type === JELLY) return; // can't fall + if (object.type === CLOUD) return; // can't fall var theseDyingObjects = []; if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; // this object can fall. maybe more will fall with it too. we'll check those separately. @@ -1930,7 +1930,7 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects } var yetAnotherObject = findObjectAtLocation(forwardLocation); if (yetAnotherObject != null) { - if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === JELLY) { + if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === CLOUD) { // not pushable return false; } @@ -2439,9 +2439,9 @@ function render() { if (!(objectHere != null && objectHere.type === FRUIT)) { drawObject(newFruit(hoverLocation)); } - } else if (paintBrushTileCode === JELLY) { - if (!(objectHere != null && objectHere.type === JELLY)) { - drawObject(newDirt(hoverLocation)); + } else if (paintBrushTileCode === CLOUD) { + if (!(objectHere != null && objectHere.type === CLOUD)) { + drawObject(newCloud(hoverLocation)); } } else if (paintBrushTileCode === "resize") { void 0; // do nothing @@ -2634,12 +2634,11 @@ function render() { //context.drawImage(img3,rowcol.c*tileSize+(tileSize*.1), rowcol.r*tileSize+(tileSize*.1), tileSize*.8, tileSize*.8); break; - case JELLY: + case CLOUD: rowcol = getRowcol(level, object.locations[0]); c = rowcol.c; r = rowcol.r; - context.fillStyle = "white"; - roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); + drawCloud(context, c*tileSize, r*tileSize); break; default: throw unreachable(); } @@ -3215,6 +3214,36 @@ function drawPlatform(r, c) { ctx.stroke(); } } + + function drawCloud(c, x, y){ + c.beginPath(); + c.moveTo(x+tileSize*0, y+tileSize*0); + + c.bezierCurveTo(x+tileSize*0, y-tileSize*.15, x+tileSize*.25, y-tileSize*.15, x+tileSize*.25, y+tileSize*0); + c.bezierCurveTo(x+tileSize*.25, y-tileSize*.15, x+tileSize*.5, y-tileSize*.15, x+tileSize*.5, y+tileSize*0); + c.bezierCurveTo(x+tileSize*.5, y-tileSize*.15, x+tileSize*.75, y-tileSize*.15, x+tileSize*.75, y+tileSize*0); + c.bezierCurveTo(x+tileSize*.75, y-tileSize*.15, x+tileSize*1, y-tileSize*.15, x+tileSize*1, y+tileSize*0); + + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*0, x+tileSize*1.15, y+tileSize*.25, x+tileSize*1, y+tileSize*.25); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.25, x+tileSize*1.15, y+tileSize*.5, x+tileSize*1, y+tileSize*.5); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.5, x+tileSize*1.15, y+tileSize*.75, x+tileSize*1, y+tileSize*.75); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.75, x+tileSize*1.15, y+tileSize*1, x+tileSize*1, y+tileSize*1); + + c.bezierCurveTo(x+tileSize*1, y+tileSize*1.15, x+tileSize*.75, y+tileSize*1.15, x+tileSize*.75, y+tileSize*1); + c.bezierCurveTo(x+tileSize*.75, y+tileSize*1.15, x+tileSize*.5, y+tileSize*1.15, x+tileSize*.5, y+tileSize*1); + c.bezierCurveTo(x+tileSize*.5, y+tileSize*1.15, x+tileSize*.25, y+tileSize*1.15, x+tileSize*.25, y+tileSize*1); + c.bezierCurveTo(x+tileSize*.25, y+tileSize*1.15, x+tileSize*0, y+tileSize*1.15, x+tileSize*0, y+tileSize*1); + + c.bezierCurveTo(x-tileSize*.15, y+tileSize*1, x-tileSize*.15, y+tileSize*.75, x+tileSize*0, y+tileSize*.75); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*.75, x-tileSize*.15, y+tileSize*.5, x+tileSize*0, y+tileSize*.5); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*.5, x-tileSize*.15, y+tileSize*.25, x+tileSize*0, y+tileSize*.25); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*.25, x-tileSize*.15, y+tileSize*0, x+tileSize*0, y+tileSize*0); + + c.closePath(); + c.fillStyle = "white"; + c.fill(); + //c.stroke(); + } function drawR(r,c,fillStyle){ //Gooby From 176a54672fd713e093fa0665529cd3c52e12d897 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 22:57:40 -0500 Subject: [PATCH 174/577] Update Experimental.html --- Experimental.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experimental.html b/Experimental.html index 9cb27b97..894705d7 100644 --- a/Experimental.html +++ b/Experimental.html @@ -41,7 +41,7 @@ - + From b4402b0046d1b5c120824351579005b608c9f1fd Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 22:58:36 -0500 Subject: [PATCH 175/577] Update Experimental.js --- Experimental.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experimental.js b/Experimental.js index a49dcea7..3e52bced 100644 --- a/Experimental.js +++ b/Experimental.js @@ -500,7 +500,7 @@ document.addEventListener("keydown", function(event) { case "F".charCodeAt(0): if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } return; - case "J".charCodeAt(0): + case "K".charCodeAt(0): if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } return; case "D".charCodeAt(0): From 586ae00c60db3090073b6da649e354d8a5555454 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 23:02:29 -0500 Subject: [PATCH 176/577] Update Experimental.html --- Experimental.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experimental.html b/Experimental.html index 894705d7..c90715ba 100644 --- a/Experimental.html +++ b/Experimental.html @@ -41,7 +41,7 @@ - + From 0f9cfbc19c4699a2b1bd99e01d0970aaa6c8f551 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 23:04:53 -0500 Subject: [PATCH 177/577] Update Experimental.js --- Experimental.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Experimental.js b/Experimental.js index 3e52bced..dd50bf98 100644 --- a/Experimental.js +++ b/Experimental.js @@ -31,7 +31,7 @@ var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM]; //Gooby var SNAKE = "s"; var BLOCK = "b"; var FRUIT = "f"; -var CLOUD = "j"; +var CLOUD = "k"; var tileSize = 34; var level; From 4ac3af92cec94071f4fd3c2a6f1e8ba1c338c6eb Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 23:20:49 -0500 Subject: [PATCH 178/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 7494ecd8..add2b099 100644 --- a/index.html +++ b/index.html @@ -571,7 +571,7 @@ - Bundók + Bundók Gooby From 5e4928c85ebe07e2b2187f126ddc06ba0487dfec Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 23:24:41 -0500 Subject: [PATCH 179/577] Update Main.js --- Main.js | 1 - 1 file changed, 1 deletion(-) diff --git a/Main.js b/Main.js index 411990d2..659d3c54 100644 --- a/Main.js +++ b/Main.js @@ -3359,4 +3359,3 @@ loadPersistentState(); if (!loadFromLocationHash()) { loadLevel(parseLevel(exampleLevel)); } - From 2ed43fbf508784062275d4942a8fd49083dc3078 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 23:26:48 -0500 Subject: [PATCH 180/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index f906fdf6..458aaa1f 100644 --- a/Framework.html +++ b/Framework.html @@ -76,6 +76,6 @@
    This game is a clone of Snakebird by Noumenon Games.
    - + From 172768b6de0e2253e29a2cf1b9ac1b04aeaa1521 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 23:46:19 -0500 Subject: [PATCH 181/577] Update Experimental.js --- Experimental.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Experimental.js b/Experimental.js index dd50bf98..3feb5ac7 100644 --- a/Experimental.js +++ b/Experimental.js @@ -3216,6 +3216,12 @@ function drawPlatform(r, c) { } function drawCloud(c, x, y){ + c.fillStyle = "white"; + c.beginPath(); + c.rect(x, y, tileSize, tileSize); + c.fill(); + c.closePath(); + c.beginPath(); c.moveTo(x+tileSize*0, y+tileSize*0); @@ -3240,9 +3246,7 @@ function drawPlatform(r, c) { c.bezierCurveTo(x-tileSize*.15, y+tileSize*.25, x-tileSize*.15, y+tileSize*0, x+tileSize*0, y+tileSize*0); c.closePath(); - c.fillStyle = "white"; c.fill(); - //c.stroke(); } From e96c93551e202fae2f35bd67c8097d9c6b1dfce7 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 9 Feb 2020 23:58:48 -0500 Subject: [PATCH 182/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index add2b099..605a0d3b 100644 --- a/index.html +++ b/index.html @@ -564,7 +564,7 @@ - Underground + Underground Gooby From 06251d1d1481a76f75886bffb6d12d0f63b533f3 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 00:00:27 -0500 Subject: [PATCH 183/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 605a0d3b..66f97083 100644 --- a/index.html +++ b/index.html @@ -564,7 +564,7 @@ - Underground + Underground Gooby From ac9209393dad5cdc048c18eb009db6e725eb3073 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 00:05:54 -0500 Subject: [PATCH 184/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 66f97083..4688e4c5 100644 --- a/index.html +++ b/index.html @@ -564,7 +564,7 @@ - Underground + Underground Gooby From 4eaf87c5ecffb21b1adde4ee5117225a71c73878 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 14:52:53 -0500 Subject: [PATCH 185/577] Update Main.js --- Main.js | 409 +++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 374 insertions(+), 35 deletions(-) diff --git a/Main.js b/Main.js index 659d3c54..ab8d344a 100644 --- a/Main.js +++ b/Main.js @@ -17,19 +17,45 @@ var img3 = document.createElement('img'); //Gooby var canvas = document.getElementById("canvas"); +var SPACE = "0".charCodeAt(0); +var WALL = "1".charCodeAt(0); +var SPIKE = "2".charCodeAt(0); +var FRUIT_v0 = "3".charCodeAt(0); //legacy +var EXIT = "4".charCodeAt(0); +var PORTAL = "5".charCodeAt(0); +var PLATFORM = "p".charCodeAt(0); +var WOODPLATFORM = "w".charCodeAt(0); +var ONEWAYWALLU = "u".charCodeAt(0); +var ONEWAYWALLD = "d".charCodeAt(0); +var ONEWAYWALLL = "l".charCodeAt(0); +var ONEWAYWALLR = "r".charCodeAt(0); +var FOAM = "f".charCodeAt(0); +var OPENGATE = "o".charCodeAt(0); +var CLOSEDGATE = "c".charCodeAt(0); + // tile codes -var SPACE = 0; +/*var SPACE = 0; var WALL = 1; var SPIKE = 2; var FRUIT_v0 = 3; // legacy var EXIT = 4; var PORTAL = 5; -var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL]; //Gooby +var PLATFORM = 6; +var WOODPLATFORM = 7; +var ONEWAYWALLU = 8; +var ONEWAYWALLD = 9; +var ONEWAYWALLL = 10; +var ONEWAYWALLR = 11; +var OPENGATE = 12; +var CLOSEDGATE = 13; +var FOAM = 14;*/ +var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, OPENGATE, CLOSEDGATE, FOAM]; // object types var SNAKE = "s"; var BLOCK = "b"; var FRUIT = "f"; +var CLOUD = "c"; var tileSize = 34; var level; @@ -114,7 +140,7 @@ function parseLevel(string) { var upconvertedObjects = []; var fruitCount = 0; for (var i = 0; i < mapData.length; i++) { - var tileCode = mapData[i].charCodeAt(0) - "0".charCodeAt(0); + var tileCode = mapData[i].charCodeAt(0); if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { // fruit used to be a tile code. now it's an object. upconvertedObjects.push({ @@ -145,6 +171,7 @@ function parseLevel(string) { if (object.type === SNAKE) locationsLimit = -1; else if (object.type === BLOCK) locationsLimit = -1; else if (object.type === FRUIT) locationsLimit = 1; + else if (object.type === CLOUD) locationsLimit = -1; else throw parserError("expected object type code"); cursor += 1; @@ -204,13 +231,17 @@ function parseLevel(string) { } } +function serializeTileCode(tileCode) { + return String.fromCharCode(tileCode); +} + function stringifyLevel(level) { var output = magicNumber + "&"; output += level.height + "&" + level.width + "\n"; output += "?\n"; for (var r = 0; r < level.height; r++) { - output += " " + level.map.slice(r * level.width, (r + 1) * level.width).join("") + "\n"; + output += " " + level.map.slice(r * level.width, (r + 1) * level.width).map(serializeTileCode).join("") + "\n"; } output += "/\n"; @@ -462,8 +493,8 @@ document.addEventListener("keydown", function(event) { if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } if (modifierMask === 0) { reset(unmoveStuff); break; } if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLR); break; } return; - case 220: // backslash if (modifierMask === 0) { toggleShowEditor(); break; } return; @@ -481,6 +512,7 @@ document.addEventListener("keydown", function(event) { case "W".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(WOODPLATFORM); break; } return; case "S".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } @@ -497,13 +529,33 @@ document.addEventListener("keydown", function(event) { case "F".charCodeAt(0): if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } return; + case "K".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } + return; case "D".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SNAKE); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLD); break; } return; case "B".charCodeAt(0): if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } return; + case "P".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } + return; + case "U".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLU); break; } + return; + case "L".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLL); break; } + return; + case "M".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FOAM); break; } + return; case "G".charCodeAt(0): if (modifierMask === 0) { toggleGrid(); break; } if ( persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } @@ -646,8 +698,18 @@ var paintButtonIdAndTileCodes = [ ["paintExitButton", EXIT], ["paintFruitButton", FRUIT], ["paintPortalButton", PORTAL], + ["paintPlatformButton", PLATFORM], + ["paintWoodPlatformButton", WOODPLATFORM], + ["paintOneWayWallUButton", ONEWAYWALLU], + ["paintOneWayWallDButton", ONEWAYWALLD], + ["paintOneWayWallLButton", ONEWAYWALLL], + ["paintOneWayWallRButton", ONEWAYWALLR], + ["paintOpenGateButton", OPENGATE], + ["paintClosedGateButton", CLOSEDGATE], + ["paintFoamButton", FOAM], ["paintSnakeButton", SNAKE], ["paintBlockButton", BLOCK], + ["paintCloudButton", CLOUD], ]; paintButtonIdAndTileCodes.forEach(function(pair) { var id = pair[0]; @@ -753,6 +815,8 @@ canvas.addEventListener("dblclick", function(event) { } else if (object.type === FRUIT) { // edit fruits, i guess paintBrushTileCode = FRUIT; + } else if (object.type === CLOUD) { + paintBrushTileCode = CLOUD; } else throw unreachable(); paintBrushTileCodeChanged(); } @@ -1096,6 +1160,19 @@ function newFruit(location) { locations: [location], }; } +function newDirt(location) { + var clouds = getObjectsOfType(CLOUD); + clouds.sort(compareId); + for (var i = 0; i < clouds.length; i++) { + if (clouds[i].id !== i) break; + } + return { + type: CLOUD, + id: i, + dead: false, // unused + locations: [location], + }; +} function paintAtLocation(location, changeLog) { if (typeof paintBrushTileCode === "number") { removeAnyObjectAtLocation(location, changeLog); @@ -1125,6 +1202,8 @@ function paintAtLocation(location, changeLog) { object.id = newBlock().id; } else if (object.type === FRUIT) { object.id = newFruit().id; + } else if (object.type === CLOUD) { + object.id = newDirt().id; } else throw unreachable(); level.objects.push(object); changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); @@ -1201,6 +1280,12 @@ function paintAtLocation(location, changeLog) { var object = newFruit(location) level.objects.push(object); changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); + } else if (paintBrushTileCode === CLOUD) { + paintTileAtLocation(location, SPACE, changeLog); + removeAnyObjectAtLocation(location, changeLog); + var object1 = newDirt(location) + level.objects.push(object1); + changeLog.push([object1.type, object1.id, serializeObjectState(null), serializeObjectState(object1)]); } else throw unreachable(); render(); } @@ -1298,7 +1383,7 @@ function reduceChangeLog(changeLog) { changeLog.splice(i, 1); i--; } - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === CLOUD) { for (var j = i + 1; j < changeLog.length; j++) { var otherChange = changeLog[j]; if (otherChange[0] === change[0] && otherChange[1] === change[1]) { @@ -1422,7 +1507,7 @@ function undoChanges(changes, changeLog) { if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; paintTileAtLocation(location, fromTileCode, changeLog); - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === CLOUD) { // change object var type = change[0]; var id = change[1]; @@ -1477,6 +1562,15 @@ function describe(arg1, arg2) { case SPIKE: return "Spikes"; case EXIT: return "an Exit"; case PORTAL: return "a Portal"; + case PLATFORM: return "a Platform"; + case WOODPLATFORM: return "a Wooden Platform"; + case ONEWAYWALLU: return "A One Way Wall (facing U)"; + case ONEWAYWALLD: return "A One Way Wall (facing D)"; + case ONEWAYWALLL: return "A One Way Wall (facing L)"; + case ONEWAYWALLR: return "A One Way Wall (facing R)"; + case OPENGATE: return "An Open Gate"; + case CLOSEDGATE: return "A Closed Gate"; + case FOAM: return "Foam"; default: throw unreachable(); } } @@ -1497,6 +1591,9 @@ function describe(arg1, arg2) { } if (arg1 === FRUIT) { return "Fruit"; + } + if (arg1 === CLOUD) { + return "Cloud"; } if (typeof arg1 === "object") return describe(arg1.type, arg1.id); throw unreachable(); @@ -1696,10 +1793,16 @@ function move(dr, dc) { var ate = false; var pushedObjects = []; + + //track OpenGates that had objects on them + var occupiedOpenGates = getOccupiedOpenGateLocations(); if (isCollision()) { var newTile = level.map[newLocation]; - if (!isTileCodeAir(newTile)) return; // can't go through that tile + if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile + if (newTile === FOAM) { + paintTileAtLocation(newLocation, SPACE, changeLog); + } var otherObject = findObjectAtLocation(newLocation); if (otherObject != null) { if (otherObject === activeSnake) return; // can't push yourself @@ -1707,6 +1810,8 @@ function move(dr, dc) { // eat removeObject(otherObject, changeLog); ate = true; + } else if (otherObject.type === CLOUD) { + removeObject(otherObject, changeLog); } else { // push objects if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; @@ -1753,6 +1858,8 @@ function move(dr, dc) { // push everything, too moveObjects(pushedObjects, dr, dc, portalLocations, portalActivationLocations, changeLog, slitherAnimations); animationQueue.push(slitherAnimations); + + occupiedOpenGates = combineOldAndNewGateOccupations(occupiedOpenGates); // gravity loop var stateToAnimationIndex = {}; @@ -1797,11 +1904,14 @@ function move(dr, dc) { } } } + + occupiedOpenGates = combineOldAndNewGateOccupations(occupiedOpenGates); // fall var dyingObjects = []; var fallingObjects = level.objects.filter(function(object) { if (object.type === FRUIT) return; // can't fall + if (object.type === CLOUD) return; // can't fall var theseDyingObjects = []; if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; // this object can fall. maybe more will fall with it too. we'll check those separately. @@ -1840,6 +1950,8 @@ function move(dr, dc) { moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); didAnything = true; } + + occupiedOpenGates = closeGates(occupiedOpenGates, changeLog); if (!didAnything) break; Array.prototype.push.apply(animationQueue, exitAnimationQueue); @@ -1850,6 +1962,28 @@ function move(dr, dc) { render(); } +function combineOldAndNewGateOccupations(oldOccupiedOpenGates) +{ + var newOccupiedOpenGates = getOccupiedOpenGateLocations(); + var newlyOccupiedOpenGates = getSetSubtract(newOccupiedOpenGates, oldOccupiedOpenGates); + return oldOccupiedOpenGates.concat(newlyOccupiedOpenGates); +} + +function closeGates(oldOccupiedOpenGates, changeLog) +{ + var newOccupiedOpenGates = getOccupiedOpenGateLocations(); + var nowUnoccupiedOpenGates = getSetSubtract(oldOccupiedOpenGates, newOccupiedOpenGates); + for (var i = 0; i < nowUnoccupiedOpenGates.length; i++) { + paintTileAtLocation(nowUnoccupiedOpenGates[i], CLOSEDGATE, changeLog); + } + return newOccupiedOpenGates; +} + +function getSetSubtract(array1, array2) { + if (array1.length === 0) return []; + return array1.filter(function(x) { return array2.indexOf(x) == -1; }); +} + function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects) { // pusher can be null (for gravity) pushedObjects.push(pushedObject); @@ -1872,9 +2006,22 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects } } var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); + if (dr === 1 && level.map[forwardLocation] === PLATFORM) { + // this platform holds us, unless we're going through it + var neighborLocations; + if (pushedObject.type === SNAKE) { + neighborLocations = []; + if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); + if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); + } else if (pushedObject.type === BLOCK) { + neighborLocations = pushedObject.locations; + } else throw asdf; + if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface + // we slip right past it + } var yetAnotherObject = findObjectAtLocation(forwardLocation); if (yetAnotherObject != null) { - if (yetAnotherObject.type === FRUIT) { + if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === CLOUD) { // not pushable return false; } @@ -1900,7 +2047,8 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects // but that means the tile must be air, // and we already know pushing that object. var tileCode = level.map[forwardLocation]; - if (!isTileCodeAir(tileCode)) { + var object = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); + if (!isTileCodeAir(pusher, object, tileCode, dr, dc)) { if (dyingObjects != null) { if (tileCode === SPIKE) { // uh... which object was this again? @@ -1970,7 +2118,7 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) for (var i = 0; i < newLocations.length; i++) { var location = newLocations[i]; - if (!isTileCodeAir(level.map[location])) return false; // blocked by tile + if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile var otherObject = findObjectAtLocation(location); if (otherObject != null && otherObject !== object) return false; // blocked by object } @@ -1988,8 +2136,18 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) return true; } -function isTileCodeAir(tileCode) { - return tileCode === SPACE || tileCode === EXIT || tileCode === PORTAL; +function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { + switch (tileCode) + { + case SPACE: case EXIT: case PORTAL: case OPENGATE: return true; + case WOODPLATFORM: case FOAM: return pusher != null; + case PLATFORM: return dr != 1; + case ONEWAYWALLU: return dr != 1; + case ONEWAYWALLD: return dr != -1; + case ONEWAYWALLL: return dc != 1; + case ONEWAYWALLR: return dc != -1; + default: return false; + } } function addIfNotPresent(array, element) { @@ -2078,6 +2236,17 @@ function getSnakes() { function getBlocks() { return getObjectsOfType(BLOCK); } +function getOccupiedOpenGateLocations() +{ + var result = []; + for (var i = 0; i < level.map.length; i++) { + if (level.map[i] === OPENGATE) { + if (findObjectAtLocation(i)) + result.push(i); + } + } + return result; +} function getObjectsOfType(type) { return level.objects.filter(function(object) { return object.type == type; @@ -2366,6 +2535,10 @@ function render() { if (typeof paintBrushTileCode === "number") { if (level.map[hoverLocation] !== paintBrushTileCode) { drawTile(paintBrushTileCode, hoverRowcol.r, hoverRowcol.c, level, hoverLocation); + if (paintBrushTileCode === PLATFORM) { + // make it bolder + hoverAlpha = 0.4; + } } } else if (paintBrushTileCode === SNAKE) { if (!(objectHere != null && objectHere.type === SNAKE && objectHere.id === paintBrushSnakeColorIndex)) { @@ -2379,6 +2552,10 @@ function render() { if (!(objectHere != null && objectHere.type === FRUIT)) { drawObject(newFruit(hoverLocation)); } + } else if (paintBrushTileCode === CLOUD) { + if (!(objectHere != null && objectHere.type === CLOUD)) { + drawObject(newDirt(hoverLocation)); + } } else if (paintBrushTileCode === "resize") { void 0; // do nothing } else if (paintBrushTileCode === "select") { @@ -2424,6 +2601,33 @@ function render() { drawCircle(r, c, 0.6, "#111"); if (activePortalLocations.indexOf(location) !== -1) drawCircle(r, c, 0.3, "#666"); break; + case PLATFORM: + drawPlatform(r, c); + break; + case WOODPLATFORM: + drawOneWayWall("#D38345", r, c, -1, 0); + break; + case ONEWAYWALLU: + drawOneWayWall("#BACFD1", r, c, -1, 0); + break; + case ONEWAYWALLD: + drawOneWayWall("#BACFD1", r, c, 1, 0); + break; + case ONEWAYWALLL: + drawOneWayWall("#BACFD1", r, c, 0, -1); + break; + case ONEWAYWALLR: + drawOneWayWall("#BACFD1", r, c, 0, 1); + break; + case OPENGATE: + drawGate(r, c, false); + break; + case CLOSEDGATE: + drawGate(r, c, true); + break; + case FOAM: + drawFoam(r, c); + break; default: throw unreachable(); } function getAdjacentTiles() { @@ -2446,6 +2650,7 @@ function render() { } function drawObject(object) { + context.save(); switch (object.type) { case SNAKE: var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); @@ -2567,35 +2772,135 @@ function render() { //context.drawImage(img3,rowcol.c*tileSize+(tileSize*.1), rowcol.r*tileSize+(tileSize*.1), tileSize*.8, tileSize*.8); break; + case CLOUD: + rowcol = getRowcol(level, object.locations[0]); + c = rowcol.c; + r = rowcol.r; + drawCloud(context, c*tileSize, r*tileSize); + break; default: throw unreachable(); + context.restore(); } + } + +function drawPlatform(r, c) { + context.fillStyle = "slategray"; + context.beginPath(); + context.moveTo(c * tileSize, r * tileSize); + context.lineTo((c + 1) * tileSize, r * tileSize); + context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.arc((c + 3/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.arc((c + 1/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.lineTo(c*tileSize, r*tileSize); + context.fill(); } + function drawOneWayWall(fillStyle, r, c, dr, dc) { + context.fillStyle = fillStyle; + if (dr == -1) + { + context.fillRect(c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15); + } + else if (dr == 1) + { + context.fillRect(c * tileSize - tileSize/15, (r + 1) * tileSize - tileSize/15 - tileSize/4, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15); + } + else if (dc == -1) + { + context.fillRect(c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15); + } + else if (dc == 1) + { + context.fillRect((c + 1) * tileSize - tileSize/15 - tileSize/4, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15); + } - function drawExit(r, c) { //Gooby - /*var cx = c+.5; - var rx = r+.5; - - var grd = context.createRadialGradient(cx*tileSize, rx*tileSize, 1, cx*tileSize, rx*tileSize, 13); - grd.addColorStop(1, "red"); - grd.addColorStop(.8, "orange"); - grd.addColorStop(.6, "yellow"); - grd.addColorStop(.4, "green"); - grd.addColorStop(.2, "blue"); - grd.addColorStop(0, "violet"); - context.fillStyle = grd; - - context.arc(cx*tileSize,rx*tileSize,tileSize/2,0,2*Math.PI); + context.lineWidth = 3; + context.strokeStyle = "#777"; + context.beginPath(); + + if (dr == -1) + { + context.moveTo(c * tileSize, r * tileSize + tileSize/2); + context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); + context.stroke(); + context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); + context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); + } + else if (dr == 1) + { + context.moveTo(c * tileSize, r * tileSize + tileSize/2); + context.lineTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); + context.stroke(); + context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); + context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); + } + else if (dc == -1) + { + context.moveTo(c * tileSize + tileSize/2, r * tileSize); + context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); + context.stroke(); + context.moveTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); + context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); + } + else if (dc == 1) + { + context.moveTo(c * tileSize + tileSize/2, r * tileSize); + context.lineTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); + context.stroke(); + context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); + context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); + } + + context.stroke(); + context.lineWidth = 0; + } + + function drawFoam(r, c) { + context.fillStyle = "white"; + for (var i = 0; i < 3; i++) { + for (var j = 0; j < 3; j++) { + context.beginPath(); + context.arc(c*tileSize + (i*2+1)*tileSize/6, r*tileSize + (j*2+1)*tileSize/6, tileSize/6, 0, 2*Math.PI); context.fill(); + } + } + } + + function drawGate(r, c, isClosed) { + if (isClosed) + { + context.lineWidth = 3; + context.strokeStyle = "#444"; + context.beginPath(); + for (var i = 1; i < 3; i++) { + context.beginPath(); + context.moveTo(c*tileSize + i*tileSize/3, r*tileSize); + context.lineTo(c*tileSize + i*tileSize/3, (r+1)*tileSize); context.stroke(); - - var img2=document.createElement('img'); - img2.src='/Snakefall/Snakebird Images/pinwheel.png'; - - if(isUneatenFruit()==0) - context.drawImage(img2,c*tileSize-tileSize/2,r*tileSize-tileSize/2,2*tileSize, 2*tileSize); - else - context.drawImage(img2,c*tileSize,r*tileSize,tileSize, tileSize);*/ + } + + for (var i = 1; i < 4; i++) { + context.beginPath(); + context.moveTo(c*tileSize, r*tileSize + i*tileSize/4 + tileSize/15); + context.lineTo((c+1)*tileSize, r*tileSize + i*tileSize/4 + tileSize/15); + context.stroke(); + } + + context.lineWidth = 0; } + + context.fillStyle = "#777"; + context.beginPath(); + context.moveTo(c*tileSize, r*tileSize); + context.lineTo((c+1)*tileSize, r*tileSize); + context.lineTo((c+1)*tileSize, (r+1)*tileSize); + context.lineTo(c*tileSize + 5*tileSize/6, (r+1)*tileSize); + context.lineTo(c*tileSize + 5*tileSize/6, r*tileSize + tileSize/2); + context.arc(c*tileSize + tileSize/2, r*tileSize + tileSize/2, tileSize/3, 0, Math.PI, true); + context.lineTo(c*tileSize + 1*tileSize/6, (r+1)*tileSize); + context.lineTo(c*tileSize, (r+1)*tileSize); + context.lineTo(c*tileSize, r*tileSize); + context.fill(); + } function drawWall(r, c, adjacentTiles) { //GOOBY //drawRect(r, c, "#976537"); @@ -3086,6 +3391,40 @@ function render() { context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); } + function drawCloud(c, x, y){ + c.fillStyle = "white"; + c.beginPath(); + c.rect(x, y, tileSize, tileSize); + c.fill(); + c.closePath(); + + c.beginPath(); + c.moveTo(x+tileSize*0, y+tileSize*0); + + c.bezierCurveTo(x+tileSize*0, y-tileSize*.15, x+tileSize*.25, y-tileSize*.15, x+tileSize*.25, y+tileSize*0); + c.bezierCurveTo(x+tileSize*.25, y-tileSize*.15, x+tileSize*.5, y-tileSize*.15, x+tileSize*.5, y+tileSize*0); + c.bezierCurveTo(x+tileSize*.5, y-tileSize*.15, x+tileSize*.75, y-tileSize*.15, x+tileSize*.75, y+tileSize*0); + c.bezierCurveTo(x+tileSize*.75, y-tileSize*.15, x+tileSize*1, y-tileSize*.15, x+tileSize*1, y+tileSize*0); + + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*0, x+tileSize*1.15, y+tileSize*.25, x+tileSize*1, y+tileSize*.25); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.25, x+tileSize*1.15, y+tileSize*.5, x+tileSize*1, y+tileSize*.5); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.5, x+tileSize*1.15, y+tileSize*.75, x+tileSize*1, y+tileSize*.75); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.75, x+tileSize*1.15, y+tileSize*1, x+tileSize*1, y+tileSize*1); + + c.bezierCurveTo(x+tileSize*1, y+tileSize*1.15, x+tileSize*.75, y+tileSize*1.15, x+tileSize*.75, y+tileSize*1); + c.bezierCurveTo(x+tileSize*.75, y+tileSize*1.15, x+tileSize*.5, y+tileSize*1.15, x+tileSize*.5, y+tileSize*1); + c.bezierCurveTo(x+tileSize*.5, y+tileSize*1.15, x+tileSize*.25, y+tileSize*1.15, x+tileSize*.25, y+tileSize*1); + c.bezierCurveTo(x+tileSize*.25, y+tileSize*1.15, x+tileSize*0, y+tileSize*1.15, x+tileSize*0, y+tileSize*1); + + c.bezierCurveTo(x-tileSize*.15, y+tileSize*1, x-tileSize*.15, y+tileSize*.75, x+tileSize*0, y+tileSize*.75); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*.75, x-tileSize*.15, y+tileSize*.5, x+tileSize*0, y+tileSize*.5); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*.5, x-tileSize*.15, y+tileSize*.25, x+tileSize*0, y+tileSize*.25); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*.25, x-tileSize*.15, y+tileSize*0, x+tileSize*0, y+tileSize*0); + + c.closePath(); + c.fill(); + } + function roundRect(ctx, x, y, width, height, radius, fill, stroke) { //Gooby if (typeof stroke === 'undefined') { stroke = true; From 0a1a8c12215ae625839f184eb169cc7c865f227c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 14:53:26 -0500 Subject: [PATCH 186/577] Update Framework.html --- Framework.html | 93 ++++++++++++++++++++++++++++---------------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/Framework.html b/Framework.html index 458aaa1f..c24debe2 100644 --- a/Framework.html +++ b/Framework.html @@ -1,48 +1,60 @@ - Snakefall - - - - + Snakefall Redesign + + + + + + - +
    @@ -54,6 +66,7 @@ Arrows/WASD to move +
    Moves: 0+0 @@ -76,6 +89,6 @@
    This game is a clone of Snakebird by Noumenon Games.
    - + From 374e4402f056cb9d7b81b68c08ecb68e379dce5c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 14:53:46 -0500 Subject: [PATCH 187/577] Create Editor.css --- Editor.css | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 Editor.css diff --git a/Editor.css b/Editor.css new file mode 100644 index 00000000..b5075be9 --- /dev/null +++ b/Editor.css @@ -0,0 +1,75 @@ +@keyframes click_me { + 0% { background-color: buttonface; } + 50% { background-color: yellow; } + 100% { background-color: buttonface; } +} + +button.click-me { + animation: click_me 1s 2 alternate; + font-weight: bold; +} + +td{ + text-align: center; +} + +button.click-me { + animation: click_me 1s 2 alternate; + font-weight: bold; +} + +body{ + font-family: Futura; + background-color: aliceblue; +} + +button{ +} + +#levelTable{ + border: 10px solid black; + margin: 0 auto; +} + +.buttonHeader{ + font-size: 10pt; +} + +#editsSpan{ + font-size: 10pt; +} + +#editText{ + font-size: 10pt; +} + +#saveLevelButton{ +} + +.standard{ + background-color: lightsteelblue; +} + +.experimental{ + background-color: lightblue; +} + +table{ + border-collapse: collapse; +} + +.spacer{ + height: 10px; +} + +.controls{ +} + +#controls{ + background-color: aliceblue; + width: 200px; +} + +.header{ + font-style: italic; +} From 1992f4c92a310b3a52395534187c284f5207daa1 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 14:54:03 -0500 Subject: [PATCH 188/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index c24debe2..fa5c8186 100644 --- a/Framework.html +++ b/Framework.html @@ -1,7 +1,7 @@ Snakefall Redesign - + From 9caa8f8a11a31c1f9400568086f5463fced93b0f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:00:49 -0500 Subject: [PATCH 189/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index fa5c8186..0bbb2281 100644 --- a/Framework.html +++ b/Framework.html @@ -89,6 +89,6 @@
    This game is a clone of Snakebird by Noumenon Games.
    - + From fbd3b3ab80447d61e1aed63d421a366ec721dfb1 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:23:01 -0500 Subject: [PATCH 190/577] Update index.html --- index.html | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/index.html b/index.html index 4688e4c5..dd627ee0 100644 --- a/index.html +++ b/index.html @@ -22,10 +22,8 @@
    Show Hidden Options
    Most checkmarks contain links to solutions, though some are not accessible without a password.
    @@ -508,70 +506,70 @@ - Under Cover + Under Cover XeroOl - Snake Filter + Snake Filter XeroOl - Platformway to Heaven + Platformway to Heaven thejoshwolfe - Under Cover 2 + Under Cover 2 XeroOl - Low Clearance + Low Clearance XeroOl - Baited Trap + Baited Trap XeroOl - Gateway to Freedom + Gateway to Freedom LevelWorld - House on Fire + House on Fire Gooby - Underground + Underground Gooby - Bundók + Bundók Gooby From 03b46cf799c3557de34de1fede7685b680123ee1 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:24:59 -0500 Subject: [PATCH 191/577] Delete Experimental.html --- Experimental.html | 83 ----------------------------------------------- 1 file changed, 83 deletions(-) delete mode 100644 Experimental.html diff --git a/Experimental.html b/Experimental.html deleted file mode 100644 index c90715ba..00000000 --- a/Experimental.html +++ /dev/null @@ -1,83 +0,0 @@ - - - Snakefall - - - - - - - - -
    - -
    -
    - Controls (hover for hotkeys): -
    - Arrows/WASD to move - - -
    - - Moves: 0+0 - - - -
    - - - - -
    This project on Github: thejoshwolfe/snakefall version ???
    -
    Check out some community made levels, and share your levels there!
    - -
    This game is a clone of Snakebird by Noumenon Games.
    - - - - From fa878409e435994b9c6a093c490b6281ac6d94b6 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:25:10 -0500 Subject: [PATCH 192/577] Delete Experimental.js --- Experimental.js | 3490 ----------------------------------------------- 1 file changed, 3490 deletions(-) delete mode 100644 Experimental.js diff --git a/Experimental.js b/Experimental.js deleted file mode 100644 index 3feb5ac7..00000000 --- a/Experimental.js +++ /dev/null @@ -1,3490 +0,0 @@ -function unreachable() { return new Error("unreachable"); } -if (typeof VERSION !== "undefined") { - document.getElementById("versionSpan").innerHTML = - '' + VERSION.tag + ''; -} -/*$(document).ready(function() { - var fruits1 = getObjectsOfType(FRUIT); - $(fruits1[0]).jqFloat({ - width: 10, - height: 10, - speed: 100 - }); -});*/ - -var img3 = document.createElement('img'); //Gooby -//img3.src = '/Snakefall/Snakebird Images/Cherry2.png'; - -var canvas = document.getElementById("canvas"); - -// tile codes -var SPACE = 0; -var WALL = 1; -var SPIKE = 2; -var FRUIT_v0 = 3; // legacy -var EXIT = 4; -var PORTAL = 5; -var PLATFORM = 6; -var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM]; //Gooby - -// object types -var SNAKE = "s"; -var BLOCK = "b"; -var FRUIT = "f"; -var CLOUD = "k"; - -var tileSize = 34; -var level; -var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; -var uneditStuff = {undoStack:[], redoStack:[], spanId:"editsSpan", undoButtonId:"uneditButton", redoButtonId:"reeditButton"}; -var paradoxes = []; -function loadLevel(newLevel) { - level = newLevel; - currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); - - activateAnySnakePlease(); - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - undoStuffChanged(unmoveStuff); - uneditStuff.undoStack = []; - uneditStuff.redoStack = []; - undoStuffChanged(uneditStuff); - blockSupportRenderCache = {}; - render(); -} - - -var magicNumber_v0 = "3tFRIoTU"; -var magicNumber = "HyRr4JK1"; -var exampleLevel = magicNumber_v0 + "&" + - "17&31" + - "?" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000040000000000" + - "0000000000000110000000000000000" + - "0000000000000111100000000000000" + - "0000000000000011000000000000000" + - "0000000000000010000010000000000" + - "0000000000000010100011000000000" + - "0000001111111000110000000110000" + - "0000011111111111111111111110000" + - "0000011111111101111111111100000" + - "0000001111111100111111111100000" + - "0000001111111000111111111100000" + - "/" + - "s0 ?351&350&349/" + - "f0 ?328/" + - "f1 ?366/"; - -var testLevel_v0 = "3tFRIoTU&5&5?0005*00300024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/"; -var testLevel_v0_converted = "HyRr4JK1&5&5?0005*4024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/f0?8/"; - -function parseLevel(string) { - // magic number - var cursor = 0; - skipWhitespace(); - var versionTag = string.substr(cursor, magicNumber.length); - switch (versionTag) { - case magicNumber_v0: - case magicNumber: break; - default: throw new Error("not a snakefall level"); - } - cursor += magicNumber.length; - consumeKeyword("&"); - - var level = { - height: -1, - width: -1, - map: [], - objects: [], - }; - - // height, width - level.height = readInt(); - consumeKeyword("&"); - level.width = readInt(); - - // map - var mapData = readRun(); - mapData = decompressSerialization(mapData); - if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); - var upconvertedObjects = []; - var fruitCount = 0; - for (var i = 0; i < mapData.length; i++) { - var tileCode = mapData[i].charCodeAt(0) - "0".charCodeAt(0); - if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { - // fruit used to be a tile code. now it's an object. - upconvertedObjects.push({ - type: FRUIT, - id: fruitCount++, - dead: false, // unused - locations: [i], - }); - tileCode = SPACE; - } - if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); - level.map.push(tileCode); - } - - // objects - skipWhitespace(); - while (cursor < string.length) { - var object = { - type: "?", - id: -1, - dead: false, - locations: [], - }; - - // type - object.type = string[cursor]; - var locationsLimit; - if (object.type === SNAKE) locationsLimit = -1; - else if (object.type === BLOCK) locationsLimit = -1; - else if (object.type === FRUIT) locationsLimit = 1; - else if (object.type === CLOUD) locationsLimit = -1; - else throw parserError("expected object type code"); - cursor += 1; - - // id - object.id = readInt(); - - // locations - var locationsData = readRun(); - var locationStrings = locationsData.split("&"); - if (locationStrings.length === 0) throw parserError("locations must be non-empty"); - if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); - - locationStrings.forEach(function(locationString) { - var location = parseInt(locationString); - if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); - object.locations.push(location); - }); - - level.objects.push(object); - skipWhitespace(); - } - for (var i = 0; i < upconvertedObjects.length; i++) { - level.objects.push(upconvertedObjects[i]); - } - - return level; - - function skipWhitespace() { - while (" \n\t\r".indexOf(string[cursor]) !== -1) { - cursor += 1; - } - } - function consumeKeyword(keyword) { - skipWhitespace(); - if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); - cursor += 1; - } - function readInt() { - skipWhitespace(); - for (var i = cursor; i < string.length; i++) { - if ("0123456789".indexOf(string[i]) === -1) break; - } - var substring = string.substring(cursor, i); - if (substring.length === 0) throw parserError("expected int"); - cursor = i; - return parseInt(substring, 10); - } - function readRun() { - consumeKeyword("?"); - var endIndex = string.indexOf("/", cursor); - var substring = string.substring(cursor, endIndex); - cursor = endIndex + 1; - return substring; - } - function parserError(message) { - return new Error("parse error at position " + cursor + ": " + message); - } -} - -function stringifyLevel(level) { - var output = magicNumber + "&"; - output += level.height + "&" + level.width + "\n"; - - output += "?\n"; - for (var r = 0; r < level.height; r++) { - output += " " + level.map.slice(r * level.width, (r + 1) * level.width).join("") + "\n"; - } - output += "/\n"; - - output += serializeObjects(level.objects); - - // sanity check - var shouldBeTheSame = parseLevel(output); - if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken - - return output; -} -function serializeObjects(objects) { - var output = ""; - for (var i = 0; i < objects.length; i++) { - var object = objects[i]; - output += object.type + object.id + " "; - output += "?" + object.locations.join("&") + "/\n"; - } - return output; -} -function serializeObjectState(object) { - if (object == null) return [0,[]]; - return [object.dead, copyArray(object.locations)]; -} - -var base66 = "----0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -function compressSerialization(string) { - string = string.replace(/\s+/g, ""); - // run-length encode several 0's in a row, etc. - // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) - var result = ""; - var runStart = 0; - for (var i = 1; i < string.length + 1; i++) { - var runLength = i - runStart; - if (string[i] === string[runStart] && runLength < base66.length - 1) continue; - // end of run - if (runLength >= 4) { - // compress - result += "*" + base66[runLength] + string[runStart]; - } else { - // literal - result += string.substring(runStart, i); - } - runStart = i; - } - return result; -} -function decompressSerialization(string) { - string = string.replace(/\s+/g, ""); - var result = ""; - for (var i = 0; i < string.length; i++) { - if (string[i] === "*") { - i += 1; - var runLength = base66.indexOf(string[i]); - i += 1; - var char = string[i]; - for (var j = 0; j < runLength; j++) { - result += char; - } - } else { - result += string[i]; - } - } - return result; -} - -var replayMagicNumber = "nmGTi8PB"; -function stringifyReplay() { - var output = replayMagicNumber + "&"; - // only specify the snake id in an input if it's different from the previous. - // the first snake index is 0 to optimize for the single-snake case. - var currentSnakeId = 0; - for (var i = 0; i < unmoveStuff.undoStack.length; i++) { - var firstChange = unmoveStuff.undoStack[i][0]; - if (firstChange[0] !== "i") throw unreachable(); - var snakeId = firstChange[1]; - var dr = firstChange[2]; - var dc = firstChange[3]; - var directionCode; - if (dr ===-1 && dc === 0) directionCode = "u"; - else if (dr === 0 && dc ===-1) directionCode = "l"; - else if (dr === 1 && dc === 0) directionCode = "d"; - else if (dr === 0 && dc === 1) directionCode = "r"; - else throw unreachable(); - if (snakeId !== currentSnakeId) { - output += snakeId; // int to string - currentSnakeId = snakeId; - } - output += directionCode; - } - return output; -} -function parseAndLoadReplay(string) { - string = decompressSerialization(string); - var expectedPrefix = replayMagicNumber + "&"; - if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); - var cursor = expectedPrefix.length; - - // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. - activeSnakeId = 0; - while (cursor < string.length) { - var snakeIdStr = ""; - var c = string.charAt(cursor); - cursor += 1; - while ('0' <= c && c <= '9') { - snakeIdStr += c; - if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); - c = string.charAt(cursor); - cursor += 1; - } - if (snakeIdStr.length > 0) { - activeSnakeId = parseInt(snakeIdStr); - // don't just validate when switching snakes, but on every move. - } - - // doing a move. - if (!getSnakes().some(function(snake) { - return snake.id === activeSnakeId; - })) { - throw new Error("invalid snake id: " + activeSnakeId); - } - switch (c) { - case 'l': move( 0, -1); break; - case 'u': move(-1, 0); break; - case 'r': move( 0, 1); break; - case 'd': move( 1, 0); break; - default: throw new Error("replay string has invalid direction: " + c); - } - } - - // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. - reset(unmoveStuff); - document.getElementById("removeButton").classList.add("click-me"); -} - -var currentSerializedLevel; -function saveLevel() { - if (isDead()) return alert("Can't save while you're dead!"); - var serializedLevel = compressSerialization(stringifyLevel(level)); - currentSerializedLevel = serializedLevel; - var hash = "#level=" + serializedLevel; - expectHash = hash; - location.hash = hash; - - // This marks a starting point for solving the level. - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - editorHasBeenTouched = false; - undoStuffChanged(unmoveStuff); -} - -function saveReplay() { - if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); - // preserve the level in the url bar. - var hash = "#level=" + currentSerializedLevel; - if (dirtyState === REPLAY_DIRTY) { - // there is a replay to save - hash += "#replay=" + compressSerialization(stringifyReplay()); - } - expectHash = hash; - location.hash = hash; -} - -function deepEquals(a, b) { - if (a == null) return b == null; - if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; - if (Array.isArray(a)) { - if (!Array.isArray(b)) return false; - if (a.length !== b.length) return false; - for (var i = 0; i < a.length; i++) { - if (!deepEquals(a[i], b[i])) return false; - } - return true; - } - // must be objects - var aKeys = Object.keys(a); - var bKeys = Object.keys(b); - if (aKeys.length !== bKeys.length) return false; - aKeys.sort(); - bKeys.sort(); - if (!deepEquals(aKeys, bKeys)) return false; - for (var i = 0; i < aKeys.length; i++) { - if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; - } - return true; -} - -function getLocation(level, r, c) { - if (!isInBounds(level, r, c)) throw unreachable(); - return r * level.width + c; -} -function getRowcol(level, location) { - if (location < 0 || location >= level.width * level.height) throw unreachable(); - var r = Math.floor(location / level.width); - var c = location % level.width; - return {r:r, c:c}; -} -function isInBounds(level, r, c) { - if (c < 0 || c >= level.width) return false;; - if (r < 0 || r >= level.height) return false;; - return true; -} -function offsetLocation(location, dr, dc) { - var rowcol = getRowcol(level, location); - return getLocation(level, rowcol.r + dr, rowcol.c + dc); -} - -var SHIFT = 1; -var CTRL = 2; -var ALT = 4; -document.addEventListener("keydown", function(event) { - var modifierMask = ( - (event.shiftKey ? SHIFT : 0) | - (event.ctrlKey ? CTRL : 0) | - (event.altKey ? ALT : 0) - ); - switch (event.keyCode) { - case 37: // left - if (modifierMask === 0) { move(0, -1); break; } - return; - case 38: // up - if (modifierMask === 0) { move(-1, 0); break; } - return; - case 39: // right - if (modifierMask === 0) { move(0, 1); break; } - return; - case 40: // down - if (modifierMask === 0) { move(1, 0); break; } - return; - case 8: // backspace - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Q".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Z".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { undo(uneditStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL|SHIFT) { redo(uneditStuff); break; } - return; - case "Y".charCodeAt(0): - if (modifierMask === 0) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { redo(uneditStuff); break; } - return; - case "R".charCodeAt(0): - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } - if (modifierMask === 0) { reset(unmoveStuff); break; } - if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } - return; - - case 220: // backslash - if (modifierMask === 0) { toggleShowEditor(); break; } - return; - case "A".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, -1); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PORTAL); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { selectAll(); break; } - return; - case "E".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - return; - case 46: // delete - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - return; - case "W".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } - return; - case "S".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPIKE); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { saveLevel(); break; } - if (!persistentState.showEditor && modifierMask === CTRL) { saveReplay(); break; } - if (modifierMask === (CTRL|SHIFT)) { saveReplay(); break; } - return; - case "X".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(EXIT); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } - return; - case "F".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } - return; - case "K".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } - return; - case "D".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SNAKE); break; } - return; - case "B".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } - return; - case "L".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } - return; - case "G".charCodeAt(0): - if (modifierMask === 0) { toggleGrid(); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } - return; - case "C".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === SHIFT) { toggleCollision(); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } - return; - case "V".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } - case "T".charCodeAt(0): - toggleTheme(); break; - return; - case 32: // spacebar - case 9: // tab - if (modifierMask === 0) { switchSnakes( 1); break; } - if (modifierMask === SHIFT) { switchSnakes(-1); break; } - return; - case "1".charCodeAt(0): - case "2".charCodeAt(0): - case "3".charCodeAt(0): - case "4".charCodeAt(0): - var index = event.keyCode - "1".charCodeAt(0); - var delta; - if (modifierMask === 0) { - delta = 1; - } else if (modifierMask === SHIFT) { - delta = -1; - } else return; - if (isAlive()) { - (function() { - var snakes = findSnakesOfColor(index); - if (snakes.length === 0) return; - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; - } - } - activeSnakeId = snakes[0].id; - })(); - } - break; - case 27: // escape - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(null); break; } - return; - default: return; - } - event.preventDefault(); - render(); -}); - -document.getElementById("switchSnakesButton").addEventListener("click", function() { - switchSnakes(1); - render(); -}); -function switchSnakes(delta) { - if (!isAlive()) return; - var snakes = getSnakes(); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; - } - } - activeSnakeId = snakes[0].id; -} -document.getElementById("showGridButton").addEventListener("click", function() { - toggleGrid(); -}); -document.getElementById("saveProgressButton").addEventListener("click", function() { - saveReplay(); -}); -document.getElementById("restartButton").addEventListener("click", function() { - reset(unmoveStuff); - render(); -}); -document.getElementById("unmoveButton").addEventListener("click", function() { - undo(unmoveStuff); - render(); -}); -document.getElementById("removeButton").addEventListener("click", function() { - redo(unmoveStuff); - render(); -}); - -document.getElementById("showHideEditor").addEventListener("click", function() { - toggleShowEditor(); -}); -function toggleShowEditor() { - persistentState.showEditor = !persistentState.showEditor; - savePersistentState(); - showEditorChanged(); -} -function toggleGrid() { - persistentState.showGrid = !persistentState.showGrid; - savePersistentState(); - render(); -} - -["serializationTextarea", "shareLinkTextbox"].forEach(function(id) { - document.getElementById(id).addEventListener("keydown", function(event) { - // let things work normally - event.stopPropagation(); - }); -}); -document.getElementById("submitSerializationButton").addEventListener("click", function() { - var string = document.getElementById("serializationTextarea").value; - try { - var newLevel = parseLevel(string); - } catch (e) { - alert(e); - return; - } - loadLevel(newLevel); -}); -document.getElementById("shareLinkTextbox").addEventListener("focus", function() { - setTimeout(function() { - document.getElementById("shareLinkTextbox").select(); - }, 0); -}); - -var paintBrushTileCode = null; -var paintBrushSnakeColorIndex = 0; -var paintBrushBlockId = 0; -var paintBrushObject = null; -var selectionStart = null; -var selectionEnd = null; -var resizeDragAnchorRowcol = null; -var clipboardData = null; -var clipboardOffsetRowcol = null; -var paintButtonIdAndTileCodes = [ - ["resizeButton", "resize"], - ["selectButton", "select"], - ["pasteButton", "paste"], - ["paintSpaceButton", SPACE], - ["paintWallButton", WALL], - ["paintSpikeButton", SPIKE], - ["paintExitButton", EXIT], - ["paintFruitButton", FRUIT], - ["paintPortalButton", PORTAL], - ["paintPlatformButton", PLATFORM], - ["paintSnakeButton", SNAKE], - ["paintBlockButton", BLOCK], - ["paintCloudButton", CLOUD], -]; -paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - document.getElementById(id).addEventListener("click", function() { - setPaintBrushTileCode(tileCode); - }); -}); -document.getElementById("uneditButton").addEventListener("click", function() { - undo(uneditStuff); - render(); -}); -document.getElementById("reeditButton").addEventListener("click", function() { - redo(uneditStuff); - render(); -}); -document.getElementById("saveLevelButton").addEventListener("click", function() { - saveLevel(); -}); -document.getElementById("copyButton").addEventListener("click", function() { - copySelection(); -}); -document.getElementById("cutButton").addEventListener("click", function() { - cutSelection(); -}); -document.getElementById("cheatGravityButton").addEventListener("click", function() { - toggleGravity(); -}); -document.getElementById("cheatCollisionButton").addEventListener("click", function() { - toggleCollision(); -}); -document.getElementById("themeButton").addEventListener("click", function() { - toggleTheme(); -}); -function toggleTheme() { - if(themeCounter"; -} -function toggleGravity() { - isGravityEnabled = !isGravityEnabled; - isCollisionEnabled = true; - refreshCheatButtonText(); -} -function toggleCollision() { - isCollisionEnabled = !isCollisionEnabled; - isGravityEnabled = false; - refreshCheatButtonText(); -} -function refreshCheatButtonText() { - document.getElementById("cheatGravityButton").textContent = isGravityEnabled ? "Gravity: ON" : "Gravity: OFF"; - document.getElementById("cheatGravityButton").style.background = isGravityEnabled ? "" : "#f88"; - - document.getElementById("cheatCollisionButton").textContent = isCollisionEnabled ? "Collision: ON" : "Collision: OFF"; - document.getElementById("cheatCollisionButton").style.background = isCollisionEnabled ? "" : "#f88"; -} - -// be careful with location vs rowcol, because this variable is used when resizing -var lastDraggingRowcol = null; -var hoverLocation = null; -var draggingChangeLog = null; -canvas.addEventListener("mousedown", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - var location = getLocationFromEvent(event); - if (persistentState.showEditor && paintBrushTileCode != null) { - // editor tool - lastDraggingRowcol = getRowcol(level, location); - if (paintBrushTileCode === "select") selectionStart = location; - if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; - draggingChangeLog = []; - paintAtLocation(location, draggingChangeLog); - } else { - // playtime - var object = findObjectAtLocation(location); - if (object == null) return; - if (object.type !== SNAKE) return; - // active snake - activeSnakeId = object.id; - render(); - } -}); -canvas.addEventListener("dblclick", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - if (persistentState.showEditor && paintBrushTileCode === "select") { - // double click with select tool - var location = getLocationFromEvent(event); - var object = findObjectAtLocation(location); - if (object == null) return; - stopDragging(); - if (object.type === SNAKE) { - // edit snakes of this color - paintBrushTileCode = SNAKE; - paintBrushSnakeColorIndex = object.id % snakeColors.length; - } else if (object.type === BLOCK) { - // edit this particular block - paintBrushTileCode = BLOCK; - paintBrushBlockId = object.id; - } else if (object.type === FRUIT) { - // edit fruits, i guess - paintBrushTileCode = FRUIT; - } else if (object.type === CLOUD) { - paintBrushTileCode = CLOUD; - } else throw unreachable(); - paintBrushTileCodeChanged(); - } -}); -document.addEventListener("mouseup", function(event) { - stopDragging(); -}); -function stopDragging() { - if (lastDraggingRowcol != null) { - // release the draggin' - lastDraggingRowcol = null; - paintBrushObject = null; - resizeDragAnchorRowcol = null; - pushUndo(uneditStuff, draggingChangeLog); - draggingChangeLog = null; - } -} -canvas.addEventListener("mousemove", function(event) { - if (!persistentState.showEditor) return; - var location = getLocationFromEvent(event); - var mouseRowcol = getRowcol(level, location); - if (lastDraggingRowcol != null) { - // Dragging Force - Through the Fruit and Flames - var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); - // we need to get rowcols for everything before we start dragging, because dragging might resize the world. - var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function(location) { - return getRowcol(level, location); - }); - path.forEach(function(rowcol) { - // convert to location at the last minute in case each of these steps is changing the coordinate system. - paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); - }); - lastDraggingRowcol = mouseRowcol; - hoverLocation = null; - } else { - // hovering - if (hoverLocation !== location) { - hoverLocation = location; - render(); - } - } -}); -canvas.addEventListener("mouseout", function() { - if (hoverLocation !== location) { - // turn off the hover when the mouse leaves - hoverLocation = null; - render(); - } -}); -function getLocationFromEvent(event) { - var r = Math.floor(eventToMouseY(event, canvas) / tileSize); - var c = Math.floor(eventToMouseX(event, canvas) / tileSize); - // since the canvas is centered, the bounding client rect can be half-pixel aligned, - // resulting in slightly out-of-bounds mouse events. - r = clamp(r, 0, level.height); - c = clamp(c, 0, level.width); - return getLocation(level, r, c); -} -function eventToMouseX(event, canvas) { return event.clientX - canvas.getBoundingClientRect().left; } -function eventToMouseY(event, canvas) { return event.clientY - canvas.getBoundingClientRect().top; } - -function selectAll() { - selectionStart = 0; - selectionEnd = level.map.length - 1; - setPaintBrushTileCode("select"); -} - -function setPaintBrushTileCode(tileCode) { - if (tileCode === "paste") { - // make sure we have something to paste - if (clipboardData == null) return; - } - if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { - // usually this means to fill in the selection - if (tileCode == null) { - // cancel selection - selectionStart = null; - selectionEnd = null; - return; - } - if (typeof tileCode === "number" && tileCode !== PORTAL) { - // fill in the selection - fillSelection(tileCode); - selectionStart = null; - selectionEnd = null; - return; - } - // ok, just select something else then. - selectionStart = null; - selectionEnd = null; - } - if (tileCode === SNAKE) { - if (paintBrushTileCode === SNAKE) { - // next snake color - paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; - } - } else if (tileCode === BLOCK) { - var blocks = getBlocks(); - if (paintBrushTileCode === BLOCK && blocks.length > 0) { - // cycle through block ids - blocks.sort(compareId); - if (paintBrushBlockId != null) { - (function() { - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id === paintBrushBlockId) { - i += 1; - if (i < blocks.length) { - // next block id - paintBrushBlockId = blocks[i].id; - } else { - // new block id - paintBrushBlockId = null; - } - return; - } - } - throw unreachable() - })(); - } else { - // first one - paintBrushBlockId = blocks[0].id; - } - } else { - // new block id - paintBrushBlockId = null; - } - } else if (tileCode == null) { - // escape - if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { - // stop editing this block, but keep the block brush selected - tileCode = BLOCK; - paintBrushBlockId = null; - } - } - paintBrushTileCode = tileCode; - paintBrushTileCodeChanged(); -} -function paintBrushTileCodeChanged() { - paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - var backgroundStyle = ""; - if (tileCode === paintBrushTileCode) { - if (tileCode === SNAKE) { - // show the color of the active snake in the color of the button - backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; - } else { - backgroundStyle = "#fdc122"; - } - } - document.getElementById(id).style.background = backgroundStyle; - }); - - var isSelectionMode = paintBrushTileCode === "select"; - ["cutButton", "copyButton"].forEach(function (id) { - document.getElementById(id).disabled = !isSelectionMode; - }); - document.getElementById("pasteButton").disabled = clipboardData == null; - - render(); -} - -function cutSelection() { - copySelection(); - fillSelection(SPACE); - render(); -} -function copySelection() { - var selectedLocations = getSelectedLocations(); - if (selectedLocations.length === 0) return; - var selectedObjects = []; - selectedLocations.forEach(function(location) { - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(selectedObjects, object); - }); - setClipboardData({ - level: JSON.parse(JSON.stringify(level)), - selectedLocations: selectedLocations, - selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), - }); -} -function setClipboardData(data) { - // find the center - var minR = Infinity; - var maxR = -Infinity; - var minC = Infinity; - var maxC = -Infinity; - data.selectedLocations.forEach(function(location) { - var rowcol = getRowcol(data.level, location); - if (rowcol.r < minR) minR = rowcol.r; - if (rowcol.r > maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var offsetR = Math.floor((minR + maxR) / 2); - var offsetC = Math.floor((minC + maxC) / 2); - - clipboardData = data; - clipboardOffsetRowcol = {r:offsetR, c:offsetC}; - paintBrushTileCodeChanged(); -} -function fillSelection(tileCode) { - var changeLog = []; - var locations = getSelectedLocations(); - locations.forEach(function(location) { - if (level.map[location] !== tileCode) { - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; - } - removeAnyObjectAtLocation(location, changeLog); - }); - pushUndo(uneditStuff, changeLog); -} -function getSelectedLocations() { - if (selectionStart == null || selectionEnd == null) return []; - var rowcol1 = getRowcol(level, selectionStart); - var rowcol2 = getRowcol(level, selectionEnd); - var r1 = rowcol1.r; - var c1 = rowcol1.c; - var r2 = rowcol2.r; - var c2 = rowcol2.c; - if (r2 < r1) { - var tmp = r1; - r1 = r2; - r2 = tmp; - } - if (c2 < c1) { - var tmp = c1; - c1 = c2; - c2 = tmp; - } - var objects = []; - var locations = []; - for (var r = r1; r <= r2; r++) { - for (var c = c1; c <= c2; c++) { - var location = getLocation(level, r, c); - locations.push(location); - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(objects, object); - } - } - // select the rest of any partially-selected objects - objects.forEach(function(object) { - object.locations.forEach(function(location) { - addIfNotPresent(locations, location); - }); - }); - return locations; -} - -function setHeight(newHeight, changeLog) { - if (newHeight < level.height) { - // crop - for (var r = newHeight; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - // also delete non-space tiles - paintTileAtLocation(location, SPACE, changeLog); - } - } - level.map.splice(newHeight * level.width); - } else { - // expand - for (var r = level.height; r < newHeight; r++) { - for (var c = 0; c < level.width; c++) { - level.map.push(SPACE); - } - } - } - changeLog.push(["h", level.height, newHeight]); - level.height = newHeight; -} -function setWidth(newWidth, changeLog) { - if (newWidth < level.width) { - // crop - for (var r = level.height - 1; r >= 0; r--) { - for (var c = level.width - 1; c >= newWidth; c--) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, SPACE, changeLog); - level.map.splice(location, 1); - } - } - } else { - // expand - for (var r = level.height - 1; r >= 0; r--) { - var insertionPoint = level.width * (r + 1); - for (var c = level.width; c < newWidth; c++) { - // boy is this inefficient. ... YOLO! - level.map.splice(insertionPoint, 0, SPACE); - } - } - } - - var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); - level.objects.forEach(function(object) { - object.locations = object.locations.map(transformLocation); - }); - - changeLog.push(["w", level.width, newWidth]); - level.width = newWidth; -} - -function newSnake(color, location) { - var snakes = findSnakesOfColor(color); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id !== i * snakeColors.length + color) break; - } - return { - type: SNAKE, - id: i * snakeColors.length + color, - dead: false, - locations: [location], - }; -} -function newBlock(location) { - var blocks = getBlocks(); - blocks.sort(compareId); - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id !== i) break; - } - return { - type: BLOCK, - id: i, - dead: false, // unused - locations: [location], - }; -} -function newFruit(location) { - var fruits = getObjectsOfType(FRUIT); - fruits.sort(compareId); - for (var i = 0; i < fruits.length; i++) { - if (fruits[i].id !== i) break; - } - return { - type: FRUIT, - id: i, - dead: false, // unused - locations: [location], - }; -} -function newCloud(location) { - var clouds = getObjectsOfType(CLOUD); - clouds.sort(compareId); - for (var i = 0; i < clouds.length; i++) { - if (clouds[i].id !== i) break; - } - return { - type: CLOUD, - id: i, - dead: false, // unused - locations: [location], - }; -} -function paintAtLocation(location, changeLog) { - if (typeof paintBrushTileCode === "number") { - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, paintBrushTileCode, changeLog); - } else if (paintBrushTileCode === "resize") { - var toRowcol = getRowcol(level, location); - var dr = toRowcol.r - resizeDragAnchorRowcol.r; - var dc = toRowcol.c - resizeDragAnchorRowcol.c; - resizeDragAnchorRowcol = toRowcol; - if (dr !== 0) setHeight(level.height + dr, changeLog); - if (dc !== 0) setWidth(level.width + dc, changeLog); - } else if (paintBrushTileCode === "select") { - selectionEnd = location; - } else if (paintBrushTileCode === "paste") { - var hoverRowcol = getRowcol(level, location); - var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); - pastedData.selectedLocations.forEach(function(location) { - var tileCode = pastedData.level.map[location]; - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, tileCode, changeLog); - }); - pastedData.selectedObjects.forEach(function(object) { - // refresh the ids so there are no collisions. - if (object.type === SNAKE) { - object.id = newSnake(object.id % snakeColors.length).id; - } else if (object.type === BLOCK) { - object.id = newBlock().id; - } else if (object.type === FRUIT) { - object.id = newFruit().id; - } else if (object.type === CLOUD) { - object.id = newCloud().id; - } else throw unreachable(); - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - }); - } else if (paintBrushTileCode === SNAKE) { - var oldSnakeSerialization = serializeObjectState(paintBrushObject); - if (paintBrushObject != null) { - // keep dragging - if (paintBrushObject.locations[0] === location) return; // we just did that - // watch out for self-intersection - var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); - if (selfIntersectionIndex !== -1) { - // truncate from here back - paintBrushObject.locations.splice(selfIntersectionIndex); - } - } - - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - if (paintBrushObject == null) { - var thereWereNoSnakes = countSnakes() === 0; - paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); - level.objects.push(paintBrushObject); - if (thereWereNoSnakes) activateAnySnakePlease(); - } else { - // extend le snake - paintBrushObject.locations.unshift(location); - } - changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); - } else if (paintBrushTileCode === BLOCK) { - var objectHere = findObjectAtLocation(location); - if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { - // just start editing this block - paintBrushBlockId = objectHere.id; - } else { - // make a change - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - var thisBlock = null; - if (paintBrushBlockId != null) { - thisBlock = findBlockById(paintBrushBlockId); - } - var oldBlockSerialization = serializeObjectState(thisBlock); - if (thisBlock == null) { - // create new block - removeAnyObjectAtLocation(location, changeLog); - thisBlock = newBlock(location); - level.objects.push(thisBlock); - paintBrushBlockId = thisBlock.id; - } else { - var existingIndex = thisBlock.locations.indexOf(location); - if (existingIndex !== -1) { - // reclicking part of this object means to delete just part of it. - if (thisBlock.locations.length === 1) { - // goodbye - removeObject(thisBlock, changeLog); - paintBrushBlockId = null; - } else { - thisBlock.locations.splice(existingIndex, 1); - } - } else { - // add a tile to the block - removeAnyObjectAtLocation(location, changeLog); - thisBlock.locations.push(location); - } - } - changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); - delete blockSupportRenderCache[thisBlock.id]; - } - } else if (paintBrushTileCode === FRUIT) { - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - var object = newFruit(location) - level.objects.push(object); - changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); - } else if (paintBrushTileCode === CLOUD) { - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - var object1 = newCloud(location) - level.objects.push(object1); - changeLog.push([object1.type, object1.id, serializeObjectState(null), serializeObjectState(object1)]); - } else throw unreachable(); - render(); -} - -function paintTileAtLocation(location, tileCode, changeLog) { - if (level.map[location] === tileCode) return; - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; -} - -function pushUndo(undoStuff, changeLog) { - // changeLog = [ - // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], - // // player input for snake 0, dr:-1, dc:0. has no effect on state. - // // "i" is always the first change in normal player movement. - // // if a changeLog does not start with "i", then it is an editor action. - // // animationQueue and freshlyRemovedAnimatedObjects - // // are used for animating re-move. - // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 - // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] - // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] - // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] - // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] - // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. - // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. - // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. - // 10, // the last change is always a declaration of the final width of the map. - // ]; - reduceChangeLog(changeLog); - if (changeLog.length === 0) return; - changeLog.push(level.width); - undoStuff.undoStack.push(changeLog); - undoStuff.redoStack = []; - paradoxes = []; - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; - - undoStuffChanged(undoStuff); -} -function reduceChangeLog(changeLog) { - for (var i = 0; i < changeLog.length - 1; i++) { - var change = changeLog[i]; - if (change[0] === "i") { - continue; // don't reduce player input - } else if (change[0] === "h") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "h") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "w") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "w") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "w") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "h") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "m") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "m" && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (change[2] === change[3]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === CLOUD) { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === change[0] && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (deepEquals(change[2], change[3])) { - // no change - changeLog.splice(i, 1); - i--; - } - } else throw unreachable(); - } -} -function undo(undoStuff) { - if (undoStuff.undoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - undoOneFrame(undoStuff); - undoStuffChanged(undoStuff); -} -function reset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.undoStack.length > 0) { - undoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); -} -function undoOneFrame(undoStuff) { - var doThis = undoStuff.undoStack.pop(); - var redoChangeLog = []; - undoChanges(doThis, redoChangeLog); - if (redoChangeLog.length > 0) { - redoChangeLog.push(level.width); - undoStuff.redoStack.push(redoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; -} -function redo(undoStuff) { - if (undoStuff.redoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - redoOneFrame(undoStuff); - undoStuffChanged(undoStuff); -} -function unreset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.redoStack.length > 0) { - redoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); - - // don't animate the last frame - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; -} -function redoOneFrame(undoStuff) { - var doThis = undoStuff.redoStack.pop(); - var undoChangeLog = []; - undoChanges(doThis, undoChangeLog); - if (undoChangeLog.length > 0) { - undoChangeLog.push(level.width); - undoStuff.undoStack.push(undoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; -} -function undoChanges(changes, changeLog) { - var widthContext = changes.pop(); - var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); - for (var i = changes.length - 1; i >= 0; i--) { - var paradoxDescription = undoChange(changes[i]); - if (paradoxDescription != null) paradoxes.push(paradoxDescription); - } - - var lastChange = changes[changes.length - 1]; - if (lastChange[0] === "i") { - // replay animation - animationQueue = lastChange[4]; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = lastChange[5]; - animationStart = new Date().getTime(); - } - - function undoChange(change) { - // note: everything here is going backwards: to -> from - if (change[0] === "i") { - // no state change, but preserve the intention. - changeLog.push(change); - return null; - } else if (change[0] === "h") { - // change height - var fromHeight = change[1]; - var toHeight = change[2]; - if (level.height !== toHeight) return "Impossible"; - setHeight(fromHeight, changeLog); - } else if (change[0] === "w") { - // change width - var fromWidth = change[1]; - var toWidth = change[2]; - if (level.width !== toWidth) return "Impossible"; - setWidth(fromWidth, changeLog); - } else if (change[0] === "m") { - // change map tile - var location = transformLocation(change[1]); - var fromTileCode = change[2]; - var toTileCode = change[3]; - if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; - if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; - paintTileAtLocation(location, fromTileCode, changeLog); - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === CLOUD) { - // change object - var type = change[0]; - var id = change[1]; - var fromDead = change[2][0]; - var toDead = change[3][0]; - var fromLocations = change[2][1].map(transformLocation); - var toLocations = change[3][1].map(transformLocation); - if (fromLocations.filter(function(location) { return location >= level.map.length; }).length > 0) { - return "Can't move " + describe(type, id) + " out of bounds"; - } - var object = findObjectOfTypeAndId(type, id); - if (toLocations.length !== 0) { - // should exist at this location - if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; - if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; - if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; - // doit - if (fromLocations.length !== 0) { - var oldState = serializeObjectState(object); - object.locations = fromLocations; - object.dead = fromDead; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - } else { - removeObject(object, changeLog); - } - } else { - // shouldn't exist - if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; - // doit - object = { - type: type, - id: id, - dead: fromDead, - locations: fromLocations, - }; - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - } - } else throw unreachable(); - } -} -function describe(arg1, arg2) { - // describe(0) -> "Space" - // describe(SNAKE, 0) -> "Snake 0 (Red)" - // describe(object) -> "Snake 0 (Red)" - // describe(BLOCK, 1) -> "Block 1" - // describe(FRUIT) -> "Fruit" - if (typeof arg1 === "number") { - switch (arg1) { - case SPACE: return "Space"; - case WALL: return "a Wall"; - case SPIKE: return "Spikes"; - case EXIT: return "an Exit"; - case PORTAL: return "a Portal"; - case PLATFORM: return "a Platform"; - default: throw unreachable(); - } - } - if (arg1 === SNAKE) { - var color = (function() { - switch (snakeColors[arg2 % snakeColors.length]) { - case "#fd0c0b": return " (Red)"; - case "#18d11f": return " (Green)"; - case "#004cff": return " (Blue)"; - case "#fdc122": return " (Yellow)"; - default: throw unreachable(); - } - })(); - return "Snake " + arg2 + color; - } - if (arg1 === BLOCK) { - return "Block " + arg2; - } - if (arg1 === FRUIT) { - return "Fruit"; - } - if (arg1 === CLOUD) { - return "Cloud"; - } - if (typeof arg1 === "object") return describe(arg1.type, arg1.id); - throw unreachable(); -} - -function undoStuffChanged(undoStuff) { - var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; - document.getElementById(undoStuff.spanId).textContent = movesText; - document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; - document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; - - // render paradox display - var uniqueParadoxes = []; - var paradoxCounts = []; - paradoxes.forEach(function(paradoxDescription) { - var index = uniqueParadoxes.indexOf(paradoxDescription); - if (index !== -1) { - paradoxCounts[index] += 1; - } else { - uniqueParadoxes.push(paradoxDescription); - paradoxCounts.push(1); - } - }); - var paradoxDivContent = ""; - uniqueParadoxes.forEach(function(paradox, i) { - if (i > 0) paradoxDivContent += "
    \n"; - if (paradoxCounts[i] > 1) paradoxDivContent += "(" + paradoxCounts[i] + "x) "; - paradoxDivContent += "Time Travel Paradox! " + uniqueParadoxes[i]; - }); - document.getElementById("paradoxDiv").innerHTML = paradoxDivContent; - - updateDirtyState(); - - if (unmoveStuff.redoStack.length === 0) { - document.getElementById("removeButton").classList.remove("click-me"); - } -} - -var CLEAN_NO_TIMELINES = 0; -var CLEAN_WITH_REDO = 1; -var REPLAY_DIRTY = 2; -var EDITOR_DIRTY = 3; -var dirtyState = CLEAN_NO_TIMELINES; -var editorHasBeenTouched = false; -function updateDirtyState() { - if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { - dirtyState = EDITOR_DIRTY; - } else if (unmoveStuff.undoStack.length > 0) { - dirtyState = REPLAY_DIRTY; - } else if (unmoveStuff.redoStack.length > 0) { - dirtyState = CLEAN_WITH_REDO; - } else { - dirtyState = CLEAN_NO_TIMELINES; - } - - var saveLevelButton = document.getElementById("saveLevelButton"); - // the save button clears your timelines - saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; - if (dirtyState >= EDITOR_DIRTY) { - // you should save - saveLevelButton.classList.add("click-me"); - saveLevelButton.textContent = "*" + "Save Level"; - } else { - saveLevelButton.classList.remove("click-me"); - saveLevelButton.textContent = "Save Level"; - } - - var saveProgressButton = document.getElementById("saveProgressButton"); - // you can't save a replay if your level is dirty - if (dirtyState === CLEAN_WITH_REDO) { - saveProgressButton.textContent = "Forget Progress"; - } else { - saveProgressButton.textContent = "Save Progress"; - } - saveProgressButton.disabled = dirtyState >= EDITOR_DIRTY || dirtyState === CLEAN_NO_TIMELINES; -} -function haveCheatcodesBeenUsed() { - return !unmoveStuff.undoStack.every(function(changeLog) { - // normal movement always starts with "i". - return changeLog[0][0] === "i"; - }); -} - -var persistentState = { - showEditor: false, - showGrid: false, -}; -function savePersistentState() { - localStorage.snakefall = JSON.stringify(persistentState); -} -function loadPersistentState() { - try { - persistentState = JSON.parse(localStorage.snakefall); - } catch (e) { - } - persistentState.showEditor = !!persistentState.showEditor; - persistentState.showGrid = !!persistentState.showGrid; - showEditorChanged(); -} -var isGravityEnabled = true; -function isGravity() { - return isGravityEnabled || !persistentState.showEditor; -} -var isCollisionEnabled = true; -function isCollision() { - return isCollisionEnabled || !persistentState.showEditor; -} -function isAnyCheatcodeEnabled() { - return persistentState.showEditor && ( - !isGravityEnabled || !isCollisionEnabled - ); -} -var themeName = "Spring"; //Gooby -var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle; -var curlyOutline = false; - -var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; -var bg2 = "rgba(254, 198, 145 * rgba(255, 192, 133"; -var bg3 = "rgba(145, 254, 198 * rgba(117, 255, 192"; -var bg4 = "rgba(7, 7, 83 * rgba(0, 0, 70"; - -var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; -var snakeColors2 = ["#f00", "#0f0", "#00f", "#ff0"]; -var snakeColors3 = ["#BA145C", "#E91624", "#F75802", "#FEFE28"]; - -var fruitColors1 = ["#ff0066","#ff36a6","#ff6b1f","#ff9900","#ff2600"]; -var fruitColors2 = ["black","black","black","black","black"]; - -var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spike, support, box, bolt -var spikeColors2 = ["black", "black", "black", "black"]; -var spikeColors3 = ["#333", "#333", "#333", "#777"]; - -var blockColors1 = [ - ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"], - ["#853641","#963c84","#753d88","#5d3a96","#3a3990"] -]; -var blockColors2 = [ - ["#f2f2f2"], - ["#f2f2f2"] -]; -var blockColors3 = [ - ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"], - ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] -]; -var blockColors4 = [ - ["#150612", "#a52e8b", "#990077", "#d917af", "#4d003c"], - ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] -]; - -var fontSize = tileSize*5; -var textStyle1 = ["" + fontSize + "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose -var textStyle2 = ["" + fontSize + "px Impact", "#5702c6", "#ff0098"]; -var textStyle3 = ["" + fontSize + "px Impact", "#BA145C", "#F75802"]; -var textStyle4 = ["" + fontSize + "px Impact", "#ff0", "#f00"]; - -var themeCounter = 0; - -var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor - //["sky",], - ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], - ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], - ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4], - ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3], - ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2], - ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1] -]; - - -function showEditorChanged() { - document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; - ["editorDiv", "editorPane"].forEach(function(id) { - document.getElementById(id).style.display = persistentState.showEditor ? "block" : "none"; - }); - document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : "/WASD"; - - render(); -} - -function move(dr, dc) { - if (!isAlive()) return; - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; - animationStart = new Date().getTime(); - var activeSnake = findActiveSnake(); - var headRowcol = getRowcol(level, activeSnake.locations[0]); - var newRowcol = {r:headRowcol.r + dr, c:headRowcol.c + dc}; - if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; - var newLocation = getLocation(level, newRowcol.r, newRowcol.c); - var changeLog = []; - - // The changeLog for a player movement starts with the input - // when playing normally. - if (!isAnyCheatcodeEnabled()) { - changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); - } - - var ate = false; - var pushedObjects = []; - - if (isCollision()) { - var newTile = level.map[newLocation]; - if (!isTileCodeAir(newTile)) return; // can't go through that tile - if (newTile === PLATFORM && dr == 1) return; // can't go down through platforms - var otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { - if (otherObject === activeSnake) return; // can't push yourself - if (otherObject.type === FRUIT) { - // eat - removeObject(otherObject, changeLog); - ate = true; - } else if (otherObject.type === CLOUD) { - removeObject(otherObject, changeLog); - } else { - // push objects - if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; - } - } - } - - // slither forward - var activeSnakeOldState = serializeObjectState(activeSnake); - var size1 = activeSnake.locations.length === 1; - var slitherAnimations = [ - 70, - [ - // size-1 snakes really do more of a move than a slither - size1 ? MOVE_SNAKE : SLITHER_HEAD, - activeSnake.id, - dr, - dc, - ] - ]; - activeSnake.locations.unshift(newLocation); - if (!ate) { - // drag your tail forward - var oldRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 1]); - var newRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 2]); - if (!size1) { - slitherAnimations.push([ - SLITHER_TAIL, - activeSnake.id, - newRowcol.r - oldRowcol.r, - newRowcol.c - oldRowcol.c, - ]); - } - activeSnake.locations.pop(); - } - changeLog.push([activeSnake.type, activeSnake.id, activeSnakeOldState, serializeObjectState(activeSnake)]); - - // did you just push your face into a portal? - var portalLocations = getActivePortalLocations(); - var portalActivationLocations = []; - if (portalLocations.indexOf(newLocation) !== -1) { - portalActivationLocations.push(newLocation); - } - // push everything, too - moveObjects(pushedObjects, dr, dc, portalLocations, portalActivationLocations, changeLog, slitherAnimations); - animationQueue.push(slitherAnimations); - - // gravity loop - var stateToAnimationIndex = {}; - if (isGravity()) for (var fallHeight = 1;; fallHeight++) { - var serializedState = serializeObjects(level.objects); - var infiniteLoopStartIndex = stateToAnimationIndex[serializedState]; - if (infiniteLoopStartIndex != null) { - // infinite loop - animationQueue.push([0, [INFINITE_LOOP, animationQueue.length - infiniteLoopStartIndex]]); - break; - } else { - stateToAnimationIndex[serializedState] = animationQueue.length; - } - // do portals separate from falling logic - if (portalActivationLocations.length === 1) { - var portalAnimations = [200]; - if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { - animationQueue.push(portalAnimations); - } - portalActivationLocations = []; - } - // now do falling logic - var didAnything = false; - var fallingAnimations = [ - 70 / Math.sqrt(fallHeight), - ]; - var exitAnimationQueue = []; - - // check for exit - if (!isUneatenFruit()) { //Gooby - var snakes = getSnakes(); - for (var i = 0; i < snakes.length; i++) { - var snake = snakes[i]; - if (level.map[snake.locations[0]] === EXIT) { - // (one of) you made it! - removeAnimatedObject(snake, changeLog); - exitAnimationQueue.push([ - 200, - [EXIT_SNAKE, snake.id, 0, 0], - ]); - didAnything = true; - } - } - } - - // fall - var dyingObjects = []; - var fallingObjects = level.objects.filter(function(object) { - if (object.type === FRUIT) return; // can't fall - if (object.type === CLOUD) return; // can't fall - var theseDyingObjects = []; - if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; - // this object can fall. maybe more will fall with it too. we'll check those separately. - theseDyingObjects.forEach(function(object) { - addIfNotPresent(dyingObjects, object); - }); - return true; - }); - if (dyingObjects.length > 0) { - var anySnakesDied = false; - dyingObjects.forEach(function(object) { - if (object.type === SNAKE) { - // look what you've done - var oldState = serializeObjectState(object); - object.dead = true; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - anySnakesDied = true; - } else if (object.type === BLOCK) { - // a box fell off the world - removeAnimatedObject(object, changeLog); - removeFromArray(fallingObjects, object); - exitAnimationQueue.push([ - 200, - [ - DIE_BLOCK, - object.id, - 0, 0 - ], - ]); - didAnything = true; - } else throw unreachable(); - }); - if (anySnakesDied) break; - } - if (fallingObjects.length > 0) { - moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); - didAnything = true; - } - - if (!didAnything) break; - Array.prototype.push.apply(animationQueue, exitAnimationQueue); - if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); - } - - pushUndo(unmoveStuff, changeLog); - render(); -} - -function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects) { - // pusher can be null (for gravity) - pushedObjects.push(pushedObject); - // find forward locations - var forwardLocations = []; - for (var i = 0; i < pushedObjects.length; i++) { - pushedObject = pushedObjects[i]; - for (var j = 0; j < pushedObject.locations.length; j++) { - var rowcol = getRowcol(level, pushedObject.locations[j]); - var forwardRowcol = {r:rowcol.r + dr, c:rowcol.c + dc}; - if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { - if (dyingObjects == null) { - // can't push things out of bounds - return false; - } else { - // this thing is going to fall out of bounds - addIfNotPresent(dyingObjects, pushedObject); - addIfNotPresent(pushedObjects, pushedObject); - continue; - } - } - var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); - if (dr === 1 && level.map[forwardLocation] === PLATFORM) { - // this platform holds us, unless we're going through it - var neighborLocations; - if (pushedObject.type === SNAKE) { - neighborLocations = []; - if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); - if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); - } else if (pushedObject.type === BLOCK) { - neighborLocations = pushedObject.locations; - } else throw asdf; - if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface - // we slip right past it - } - var yetAnotherObject = findObjectAtLocation(forwardLocation); - if (yetAnotherObject != null) { - if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === CLOUD) { - // not pushable - return false; - } - if (yetAnotherObject === pusher) { - // indirect pushing ourselves. - // special check for when we're indirectly pushing the tip of our own tail. - if (forwardLocation === pusher.locations[pusher.locations.length -1]) { - // for some reason this is ok. - continue; - } - return false; - } - addIfNotPresent(pushedObjects, yetAnotherObject); - } else { - addIfNotPresent(forwardLocations, forwardLocation); - } - } - } - // check forward locations - for (var i = 0; i < forwardLocations.length; i++) { - var forwardLocation = forwardLocations[i]; - // many of these locations can be inside objects, - // but that means the tile must be air, - // and we already know pushing that object. - var tileCode = level.map[forwardLocation]; - if (!isTileCodeAir(tileCode)) { - if (dyingObjects != null) { - if (tileCode === SPIKE) { - // uh... which object was this again? - var deadObject = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); - if (deadObject.type === SNAKE) { - // ouch! - addIfNotPresent(dyingObjects, deadObject); - continue; - } - } - } - // can't push into something solid - return false; - } - } - // the push is go - return true; -} - -function activateAnySnakePlease() { - var snakes = getSnakes(); - if (snakes.length === 0) return; // nope.avi - activeSnakeId = snakes[0].id; -} - -function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations, changeLog, animations) { - objects.forEach(function(object) { - var oldState = serializeObjectState(object); - var oldPortals = getSetIntersection(portalLocations, object.locations); - for (var i = 0; i < object.locations.length; i++) { - object.locations[i] = offsetLocation(object.locations[i], dr, dc); - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - animations.push([ - "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK - object.id, - dr, - dc, - ]); - - var newPortals = getSetIntersection(portalLocations, object.locations); - var activatingPortals = newPortals.filter(function(portalLocation) { - return oldPortals.indexOf(portalLocation) === -1; - }); - if (activatingPortals.length === 1) { - // exactly one new portal we're touching. activate it - portalActivationLocations.push(activatingPortals[0]); - } - }); -} - -function activatePortal(portalLocations, portalLocation, animations, changeLog) { - var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; - var portalRowcol = getRowcol(level, portalLocation); - var otherPortalRowcol = getRowcol(level, otherPortalLocation); - var delta = {r:otherPortalRowcol.r - portalRowcol.r, c:otherPortalRowcol.c - portalRowcol.c}; - - var object = findObjectAtLocation(portalLocation); - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r + delta.r; - var c = rowcol.c + delta.c; - if (!isInBounds(level, r, c)) return false; // out of bounds - newLocations.push(getLocation(level, r, c)); - } - - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (!isTileCodeAir(level.map[location])) return false; // blocked by tile - var otherObject = findObjectAtLocation(location); - if (otherObject != null && otherObject !== object) return false; // blocked by object - } - - // zappo presto! - var oldState = serializeObjectState(object); - object.locations = newLocations; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - animations.push([ - "t" + object.type, // TELEPORT_SNAKE | TELEPORT_BLOCK - object.id, - delta.r, - delta.c, - ]); - return true; -} - -function isTileCodeAir(tileCode) { - return tileCode === SPACE || tileCode === EXIT || tileCode === PORTAL || tileCode === PLATFORM; -} - -function addIfNotPresent(array, element) { - if (array.indexOf(element) !== -1) return; - array.push(element); -} -function removeAnyObjectAtLocation(location, changeLog) { - var object = findObjectAtLocation(location); - if (object != null) removeObject(object, changeLog); -} -function removeAnimatedObject(object, changeLog) { - removeObject(object, changeLog); - freshlyRemovedAnimatedObjects.push(object); -} -function removeObject(object, changeLog) { - removeFromArray(level.objects, object); - changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0,[]]]); - if (object.type === SNAKE && object.id === activeSnakeId) { - activateAnySnakePlease(); - } - if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { - // no longer editing an object that doesn't exit - paintBrushBlockId = null; - } - if (object.type === BLOCK) { - delete blockSupportRenderCache[object.id]; - } -} -function removeFromArray(array, element) { - var index = array.indexOf(element); - if (index === -1) throw unreachable(); - array.splice(index, 1); -} -function findActiveSnake() { - var snakes = getSnakes(); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) return snakes[i]; - } - throw unreachable(); -} -function findBlockById(id) { - return findObjectOfTypeAndId(BLOCK, id); -} -function findSnakesOfColor(color) { - return level.objects.filter(function(object) { - if (object.type !== SNAKE) return false; - return object.id % snakeColors.length === color; - }); -} -function findObjectOfTypeAndId(type, id) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.type === type && object.id === id) return object; - } - return null; -} -function findObjectAtLocation(location) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.locations.indexOf(location) !== -1) - return object; - } - return null; -} -function isUneatenFruit() { - return getObjectsOfType(FRUIT).length > 0; -} -function getActivePortalLocations() { - var portalLocations = getPortalLocations(); - if (portalLocations.length !== 2) return []; // nice try - return portalLocations; -} -function getPortalLocations() { - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === PORTAL) result.push(i); - } - return result; -} -function countSnakes() { - return getSnakes().length; -} -function getSnakes() { - return getObjectsOfType(SNAKE); -} -function getBlocks() { - return getObjectsOfType(BLOCK); -} -function getObjectsOfType(type) { - return level.objects.filter(function(object) { - return object.type == type; - }); -} -function isDead() { - if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; - return getSnakes().filter(function(snake) { - return !!snake.dead; - }).length > 0; -} -function isAlive() { - return countSnakes() > 0 && !isDead(); -} - - -var snakeAltColors = [ - "#ff6666", - "#66ff66", - "#6666ff", - "#ffff66", -]; - -var activeSnakeId = null; - -var SLITHER_HEAD = "sh"; -var SLITHER_TAIL = "st"; -var MOVE_SNAKE = "ms"; -var MOVE_BLOCK = "mb"; -var TELEPORT_SNAKE = "ts"; -var TELEPORT_BLOCK = "tb"; -var EXIT_SNAKE = "es"; -var DIE_SNAKE = "ds"; -var DIE_BLOCK = "db"; -var INFINITE_LOOP = "il"; -var animationQueue = [ - // // sequence of disjoint animation groups. - // // each group completes before the next begins. - // [ - // 70, // duration of this animation group - // // multiple things to animate simultaneously - // [ - // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, - // objectId, - // dr, - // dc, - // ], - // [ - // INFINITE_LOOP, - // loopSizeNotIncludingThis, - // ], - // ], -]; -var animationQueueCursor = 0; -var animationStart = null; // new Date().getTime() -var animationProgress; // 0.0 <= x < 1.0 -var freshlyRemovedAnimatedObjects = []; - -// render the support beams for blocks into a temporary buffer, and remember it. -// this is due to stencil buffers causing slowdown on some platforms. see #25. -var blockSupportRenderCache = { - // id: canvas, - // "0": document.createElement("canvas"), -}; - -function render() { - if (level == null) return; - if (animationQueueCursor < animationQueue.length) { - var animationDuration = animationQueue[animationQueueCursor][0]; - animationProgress = (new Date().getTime() - animationStart) / animationDuration; - if (animationProgress >= 1.0) { - // animation group complete - animationProgress -= 1.0; - animationQueueCursor++; - if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { - var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; - animationQueueCursor -= infiniteLoopSize; - } - animationStart = new Date().getTime(); - } - } - if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; - canvas.width = tileSize * level.width; - canvas.height = tileSize * level.height; - var context = canvas.getContext("2d"); //Gooby - - themeName = themes[themeCounter][0]; - if(themeName!="sky"){ - background = themes[themeCounter][1]; - material = themes[themeCounter][2]; - surface = themes[themeCounter][3]; - snakeColors = themes[themeCounter][5]; - blockColors = themes[themeCounter][6]; - spikeColors = themes[themeCounter][7]; - fruitColors = themes[themeCounter][8]; - textStyle = themes[themeCounter][10]; - - curlyOutline = themes[themeCounter][4]; - if(background.substr(0,1) == "#") { - context.fillStyle = background; - context.fillRect(0, 0, canvas.width, canvas.height); - } - else{ - for(var i = 0; i maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var image = blockSupportRenderCache[object.id]; - if (image == null) { - // render the support beams to a buffer - blockSupportRenderCache[object.id] = image = document.createElement("canvas"); - image.width = (maxC - minC + 1) * tileSize; - image.height = (maxR - minR + 1) * tileSize; - var bufferContext = image.getContext("2d"); - // Make a stencil that excludes the insides of blocks. - // Then when we render the support beams, we won't see the supports inside the block itself. - bufferContext.beginPath(); - // Draw a path around the whole screen in the opposite direction as the rectangle paths below. - // This means that the below rectangles will be removing area from the greater rectangle. - bufferContext.rect(image.width, 0, -image.width, image.height); - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r - minR; - var c = rowcol.c - minC; - bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); - } - bufferContext.clip(); - for (var i = 0; i < object.locations.length - 1; i++) { - var rowcol1 = getRowcol(level, object.locations[i]); - rowcol1.r -= minR; - rowcol1.c -= minC; - var rowcol2 = getRowcol(level, object.locations[i + 1]); - rowcol2.r -= minR; - rowcol2.c -= minC; - var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; - drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - } - } - var r = minR + animationDisplacementRowcol.r; - var c = minC + animationDisplacementRowcol.c; - context.drawImage(image, c * tileSize, r * tileSize); - }); - - // terrain - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - var tileCode = level.map[location]; - drawTile(tileCode, r, c, level, location); - } - } - } - - // objects - objects.forEach(drawObject); - - // banners - if (countSnakes() === 0) { - context.fillStyle = textStyle[1]; - context.font = textStyle[0]; - context.shadowOffsetX = 5; - context.shadowOffsetY = 5; - context.shadowColor = "rgba(0,0,0,0.5)"; - context.shadowBlur = 4; - var textString = "WIN"; - var textWidth = context.measureText(textString).width; - context.fillText(textString, (canvas.width/2) - (textWidth/2), canvas.height/2); - } - if (isDead()) { - context.fillStyle = textStyle[2]; - context.font = textStyle[0]; - context.shadowOffsetX = 5; - context.shadowOffsetY = 5; - context.shadowColor = "rgba(0,0,0,0.5)"; - context.shadowBlur = 4; - textString = "LOSE"; - textWidth = context.measureText(textString).width; - context.fillText(textString, (canvas.width/2) - (textWidth/2), canvas.height/2); - } - - // editor hover - if (persistentState.showEditor && paintBrushTileCode != null && hoverLocation != null && hoverLocation < level.map.length) { - - var savedContext = context; - var buffer = document.createElement("canvas"); - buffer.width = canvas.width; - buffer.height = canvas.height; - context = buffer.getContext("2d"); - - var hoverRowcol = getRowcol(level, hoverLocation); - var objectHere = findObjectAtLocation(hoverLocation); - if (typeof paintBrushTileCode === "number") { - if (level.map[hoverLocation] !== paintBrushTileCode) { - drawTile(paintBrushTileCode, hoverRowcol.r, hoverRowcol.c, level, hoverLocation); - if (paintBrushTileCode === PLATFORM) { - // make it bolder - hoverAlpha = 0.4; - } - } - } else if (paintBrushTileCode === SNAKE) { - if (!(objectHere != null && objectHere.type === SNAKE && objectHere.id === paintBrushSnakeColorIndex)) { - drawObject(newSnake(paintBrushSnakeColorIndex, hoverLocation)); - } - } else if (paintBrushTileCode === BLOCK) { - if (!(objectHere != null && objectHere.type === BLOCK && objectHere.id === paintBrushBlockId)) { - drawObject(newBlock(hoverLocation)); - } - } else if (paintBrushTileCode === FRUIT) { - if (!(objectHere != null && objectHere.type === FRUIT)) { - drawObject(newFruit(hoverLocation)); - } - } else if (paintBrushTileCode === CLOUD) { - if (!(objectHere != null && objectHere.type === CLOUD)) { - drawObject(newCloud(hoverLocation)); - } - } else if (paintBrushTileCode === "resize") { - void 0; // do nothing - } else if (paintBrushTileCode === "select") { - void 0; // do nothing - } else if (paintBrushTileCode === "paste") { - // show what will be pasted if you click - var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); - pastedData.selectedLocations.forEach(function(location) { - var tileCode = pastedData.level.map[location]; - var rowcol = getRowcol(level, location); - drawTile(tileCode, rowcol.r, rowcol.c, pastedData.level, location); - }); - pastedData.selectedObjects.forEach(drawObject); - } else throw unreachable(); - - context = savedContext; - context.save(); - context.globalAlpha = 0.2; - context.drawImage(buffer, 0, 0); - context.restore(); - } - } - function drawTile(tileCode, r, c, level, location) { - switch (tileCode) { - case SPACE: - break; - case WALL: - drawWall(r, c, getAdjacentTiles()); - break; - case SPIKE: - drawSpikes(r, c, getAdjacentTiles(), level); - break; - case EXIT: - //drawExit(r, c); - var radiusFactor = isUneatenFruit() ? 0.7 : 1.2; - drawQuarterPie(r, c, radiusFactor, snakeColors[0], 0); - drawQuarterPie(r, c, radiusFactor, snakeColors[1], 1); - drawQuarterPie(r, c, radiusFactor, snakeColors[2], 2); - drawQuarterPie(r, c, radiusFactor, snakeColors[3], 3); - break; - case PORTAL: - drawCircle(r, c, 0.8, "#888"); - drawCircle(r, c, 0.6, "#111"); - if (activePortalLocations.indexOf(location) !== -1) drawCircle(r, c, 0.3, "#666"); - break; - case PLATFORM: - drawPlatform(r, c); - break; - default: throw unreachable(); - } - function getAdjacentTiles() { - return [ - [getTile(r - 1, c - 1), - getTile(r - 1, c + 0), - getTile(r - 1, c + 1)], - [getTile(r + 0, c - 1), - null, - getTile(r + 0, c + 1)], - [getTile(r + 1, c - 1), - getTile(r + 1, c + 0), - getTile(r + 1, c + 1)], - ]; - } - function getTile(r, c) { - if (!isInBounds(level, r, c)) return null; - return level.map[getLocation(level, r, c)]; - } - } - - function drawObject(object) { - switch (object.type) { - case SNAKE: - var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); - var lastRowcol = null - var color = snakeColors[object.id % snakeColors.length]; - //var altColor = snakeAltColors[object.id % snakeAltColors.length]; - var headRowcol; - for (var i = 0; i <= object.locations.length; i++) { - var animation; - var rowcol; - if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { - // animate head slithering forward - rowcol = getRowcol(level, object.locations[i]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else if (i === object.locations.length) { - // animated tail? - if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { - // animate tail slithering to catch up - rowcol = getRowcol(level, object.locations[i - 1]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else { - // no animated tail needed - break; - } - } else { - rowcol = getRowcol(level, object.locations[i]); - } - if (object.dead) rowcol.r += 0.5; - rowcol.r += animationDisplacementRowcol.r; - rowcol.c += animationDisplacementRowcol.c; - if (i === 0) { - // head - headRowcol = rowcol; - drawDiamond(rowcol.r, rowcol.c, color); - } else { - // middle - var cx = (rowcol.c + 0.5) * tileSize; - var cy = (rowcol.r + 0.5) * tileSize; - /*if(i % 2 == 0)*/ context.fillStyle = color; - //else context.fillStyle = altColor; - var orientation; - if (lastRowcol.r < rowcol.r) { - orientation = 0; - context.beginPath(); - context.moveTo((lastRowcol.c + 0) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.lineTo((lastRowcol.c + 1) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.arc(cx, cy, tileSize/2, 0, Math.PI); - context.fill(); - } else if (lastRowcol.r > rowcol.r) { - orientation = 2; - context.beginPath(); - context.moveTo((lastRowcol.c + 1) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.lineTo((lastRowcol.c + 0) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.arc(cx, cy, tileSize/2, Math.PI, 0); - context.fill(); - } else if (lastRowcol.c < rowcol.c) { - orientation = 3; - context.beginPath(); - context.moveTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 1) * tileSize); - context.lineTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 0) * tileSize); - context.arc(cx, cy, tileSize/2, 1.5 * Math.PI, 2.5 * Math.PI); - context.fill(); - } else if (lastRowcol.c > rowcol.c) { - orientation = 1; - context.beginPath(); - context.moveTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 0) * tileSize); - context.lineTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 1) * tileSize); - context.arc(cx, cy, tileSize/2, 2.5 * Math.PI, 1.5 * Math.PI); - context.fill(); - } - } - lastRowcol = rowcol; - } - // eye - if (object.id === activeSnakeId) { - drawCircle(headRowcol.r, headRowcol.c, 0.5, "#fff"); - drawCircle(headRowcol.r, headRowcol.c, 0.2, "#000"); - } - break; - case BLOCK: - drawBlock(object); - break; - case FRUIT: //Gooby - rowcol = getRowcol(level, object.locations[0]); - var c = rowcol.c; - var r = rowcol.r; - var startC = c*tileSize+tileSize/2; - var startR = r*tileSize+tileSize*.2; - var resize = tileSize * 1.7; - context.fillStyle = fruitColors[object.id % fruitColors.length]; - if(themeName != "Classic"){ - if(surface == "rainbow") { - context.fillStyle = "black"; - context.lineWidth = tileSize/8; - context.strokeStyle = "white"; - resize = tileSize * 1.4; - } - //context.fillStyle = "#ff6b45"; - context.beginPath(); - context.moveTo(startC, startR); - context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC-resize*.25, startR-resize*.1, startC-resize*.3, startR+resize*.05); - context.bezierCurveTo(startC-resize*.35, startR+resize*.15, startC-resize*.3, startR+resize*.6, startC, startR+resize*.5); - context.bezierCurveTo(startC+resize*.3, startR+resize*.6, startC+resize*.35, startR+resize*.15, startC+resize*.3, startR+resize*.05); - context.bezierCurveTo(startC+resize*.25, startR-resize*.05, startC+resize*.1, startR-resize*.1, startC, startR); - context.closePath(); - context.fill(); - if(surface == "rainbow") context.stroke(); - - context.beginPath(); - context.moveTo(startC,startR); - context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); - context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); - context.fillStyle = themes[themeCounter][9]; - context.fill(); - } - else drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); - - //context.drawImage(img3,rowcol.c*tileSize+(tileSize*.1), rowcol.r*tileSize+(tileSize*.1), tileSize*.8, tileSize*.8); - break; - case CLOUD: - rowcol = getRowcol(level, object.locations[0]); - c = rowcol.c; - r = rowcol.r; - drawCloud(context, c*tileSize, r*tileSize); - break; - default: throw unreachable(); - } - } - - function drawExit(r, c) { //Gooby - /*var cx = c+.5; - var rx = r+.5; - - var grd = context.createRadialGradient(cx*tileSize, rx*tileSize, 1, cx*tileSize, rx*tileSize, 13); - grd.addColorStop(1, "red"); - grd.addColorStop(.8, "orange"); - grd.addColorStop(.6, "yellow"); - grd.addColorStop(.4, "green"); - grd.addColorStop(.2, "blue"); - grd.addColorStop(0, "violet"); - context.fillStyle = grd; - - context.arc(cx*tileSize,rx*tileSize,tileSize/2,0,2*Math.PI); - context.fill(); - context.stroke(); - - var img2=document.createElement('img'); - img2.src='/Snakefall/Snakebird Images/pinwheel.png'; - - if(isUneatenFruit()==0) - context.drawImage(img2,c*tileSize-tileSize/2,r*tileSize-tileSize/2,2*tileSize, 2*tileSize); - else - context.drawImage(img2,c*tileSize,r*tileSize,tileSize, tileSize);*/ - } - -function drawDirt(r, c) { - drawRect(r, c, "#d37c2a"); - context.fillStyle = "#844204"; - context.beginPath(); - context.moveTo(c*tileSize + tileSize/2, r*tileSize); - context.lineTo((c+1)*tileSize, r*tileSize + tileSize/2); - context.lineTo(c*tileSize + tileSize/2, (r+1)*tileSize); - context.lineTo(c*tileSize, r*tileSize + tileSize/2); - context.lineTo(c*tileSize + tileSize/2, r*tileSize); - context.fill(); - } - -function drawPlatform(r, c) { - context.fillStyle = "#b9733d"; - context.beginPath(); - context.moveTo(c * tileSize, r * tileSize); - context.lineTo((c + 1) * tileSize, r * tileSize); - context.arc((c + 3/4) * tileSize, (r + 1/4) * tileSize, tileSize/4, 0, Math.PI); - context.arc((c + 1/4) * tileSize, (r + 1/4) * tileSize, tileSize/4, 0, Math.PI); - context.fill(); - } - - function drawWall(r, c, adjacentTiles) { //GOOBY - //drawRect(r, c, "#976537"); - drawTileNew(r, c, isWall, 0.2, material, curlyOutline); - drawTileOutlines(r, c, isWall, 0.2, curlyOutline); - context.save(); - if(curlyOutline) drawBushes(r, c, isWall); - context.restore(); - context.fillStyle = "#895C33"; // dirt edge - //drawTileOutlines(r, c, isWall, 0.2, false); - - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; - } - } - - function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle, curlyOutline){ - context.fillStyle = fillStyle; - var tileColor = "blue"; - if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10,br:10}, true, false); - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10}, true, false); - else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {br:10}, true, false); - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); - else roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); - - if(isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { - context.fillRect((c+1)*tileSize, (r+1)*tileSize, tileSize/6, tileSize/6); - //context.globalCompositeOperation = "destination-out"; - context.beginPath(); - context.arc((c+1)*tileSize+tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); - context.closePath(); - - var bgColor; - if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*')+2, background.length); - var r1, r2, b1, b2, g1, g2; - r1 = bgColor.substr(5, bgColor.indexOf(",")-5); - g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); - b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); - var shade = (r+1)*.03+.5; - if(shade>1) - shade = 1; - r2 = 255 + (r1-255) * shade; - g2 = 255 + (g1-255) * shade; - b2 = 255 + (b1-255) * shade; - context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; - context.fill(); - context.globalCompositeOperation = "source-over"; - } - if(isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1) && curlyOutline) { - context.fillRect(c*tileSize-tileSize/6, (r+1)*tileSize, tileSize/6, tileSize/6); - //context.globalCompositeOperation = "destination-out"; - context.beginPath(); - context.arc(c*tileSize-tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); - context.closePath(); - - var bgColor; - if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*')+2, background.length); - var r1, r2, b1, b2, g1, g2; - r1 = bgColor.substr(5, bgColor.indexOf(",")-5); - g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); - b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); - var shade = (r+1)*.03+.5; - if(shade>1) - shade = 1; - r2 = 255 + (r1-255) * shade; - g2 = 255 + (g1-255) * shade; - b2 = 255 + (b1-255) * shade; - context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; - context.fill(); - context.globalCompositeOperation = "source-over"; - } - } - - function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { //Gooby - if(surface != "rainbow") { - context.fillStyle = surface; - } - else{ - context.fillStyle = "white"; - var mod = (r+c) % 17; - switch(mod){ - case 0: context.fillStyle = "#ff004c"; break; - case 1: context.fillStyle = "#e30000"; break; - case 2: context.fillStyle = "#ff4c00"; break; - case 3: context.fillStyle = "#ff9900"; break; - case 4: context.fillStyle = "#ffe500"; break; - case 5: context.fillStyle = "#cbff00"; break; - case 6: context.fillStyle = "#7fff00"; break; - case 7: context.fillStyle = "#00ff19"; break; - case 8: context.fillStyle = "#00ff66"; break; - case 9: context.fillStyle = "#00ffb2"; break; - case 10: context.fillStyle = "#00ffff"; break; - case 11: context.fillStyle = "#00b2ff"; break; - case 12: context.fillStyle = "#3200ff"; break; - case 13: context.fillStyle = "#5702c6"; break; - case 14: context.fillStyle = "#cc00ff"; break; - case 15: context.fillStyle = "#ff00e5"; break; - case 16: context.fillStyle = "#ff0098"; break; - } - } - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - var complementPixels = (1 - 2 * outlineThickness) * tileSize; - - - if (curlyOutline && !isOccupied(0, -1)){ - if(!isOccupied(-1, 0) && isOccupied(1, 0)){ - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.4, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize); - context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); - context.closePath(); - } - else if(isOccupied(-1, 0) && !isOccupied(1, 0)){ - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.95, r*tileSize+tileSize*.3, c*tileSize+tileSize*.7, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.65, r*tileSize+tileSize*.4, c*tileSize+tileSize*.4, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.1, r*tileSize+tileSize*.4, c*tileSize, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize); - context.bezierCurveTo((c+1)*tileSize+tileSize*.2, r*tileSize-tileSize*.05, (c+1)*tileSize+tileSize*.15, r*tileSize+tileSize*.5, (c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.25); - context.closePath(); - } - else if(!isOccupied(-1, 0) && !isOccupied(1, 0)){ - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.9, r*tileSize-tileSize*0); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize); - context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); - context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.8, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); - context.bezierCurveTo((c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.4, (c+1)*tileSize+tileSize*.3, r*tileSize+tileSize*.3, (c+1)*tileSize, r*tileSize+tileSize*.02); - context.closePath(); - } - else{ - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize+tileSize*.15); - context.bezierCurveTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.4, c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.3, c*tileSize+tileSize*.6, r*tileSize+tileSize*.3, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize, r*tileSize); - context.closePath(); - } - context.fill(); - } - else if(!curlyOutline && !isOccupied(0, -1)){ context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - - } - if (!curlyOutline && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (!curlyOutline && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!curlyOutline && !isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); - } - - function drawBushes(r, c, isOccupied){ - if(!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)){ - /*context.shadowColor = "#666"; - context.shadowOffsetX = -.5; - context.shadowOffsetY = -.5; - context.shadowBlur = 1;*/ - - context.beginPath(); - context.moveTo((c+1)*tileSize, r*tileSize); - context.lineTo((c+1)*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); - context.lineTo((c+1)*tileSize, r*tileSize); - context.closePath(); - context.fill(); - - context.beginPath(); - context.moveTo((c+1)*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); - } - - if(!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)){ - /*context.shadowColor = "#666"; - context.shadowOffsetX = .5; - context.shadowOffsetY = -.5; - context.shadowBlur = 1;*/ - - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); - context.lineTo(c*tileSize, r*tileSize); - context.closePath(); - context.fill(); - - context.restore(); - - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); - /*context.strokeStyle = "#7dff1a"; - context.stroke();*/ - } - } - - function drawTileOutlines2(r, c, isOccupied, outlineThickness) { - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - var complementPixels = (1 - 2 * outlineThickness) * tileSize; - if (!isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - if (!isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (!isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); - } - - function drawSpikes(r, c, adjacentTiles) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = spikeColors[0]; - - context.beginPath(); - context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes - context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.45, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.55, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.75, y + tileSize * 0.3); - - context.moveTo(x + tileSize * 0.7, y + tileSize * 0.25); //right spikes - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.45); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.55); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.75); - - context.moveTo(x + tileSize * 0.75, y + tileSize * 0.7); //bottom spikes - context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.55, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.45, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.25, y + tileSize * 0.7); - - context.moveTo(x + tileSize * 0.3, y + tileSize * 0.75); //left spikes - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.55); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.45); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); - context.closePath(); - - /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ - context.fill(); - drawSpikeSupports(r, c, isSpike, isWall); - - function isSpike(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === SPIKE; - } - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; - } - } - - function drawSpikeSupports(r, c, isOccupied, canConnect){ - var boltBool = false; - var occupiedCount = 0; - if(canConnect(0, 1)){ - context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize+(tileSize*.3), r*tileSize+(tileSize*.8), tileSize*.4, tileSize*.4); - boltBool = true; - } - if(canConnect(0, -1) && !canConnect(0, 1)){ - if(!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(1, -1)){} - else{ - context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize+(tileSize*.3), r*tileSize, tileSize*.4, tileSize*.4); - boltBool = true; - } - } - if(canConnect(-1, 0) && !canConnect(0, 1)){ - if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(-1, 1)){} - else{ - context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize, r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); - boltBool = true; - } - } - if(canConnect(1, 0) && !canConnect(0, 1)){ - if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(1, -1) && canConnect(1, 1)){} - else{ - context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize+(tileSize*.8), r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); - boltBool = true; - } - } - - context.fillStyle = spikeColors[2]; - if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING ONE - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4,br:4}, true, false); - boltBool = true; - } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize, tileSize*.6, {tl:4,bl:4}, true, false); - boltBool = true; - } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4,tr:4}, true, false); - boltBool = true; - } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4,br:4}, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (CORNERS) - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {bl:4}, true, false); - if(!canConnect(1, -1)) boltBool = true; - } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {br:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {br:4}, true, false); - if(!canConnect(-1, -1)) boltBool = true; - } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tl:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4}, true, false); - if(!canConnect(1, 1)) boltBool = true; - } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tr:4}, true, false); - if(!canConnect(-1, 1)) boltBool = true; - } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (OPPOSITES) - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); - } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - } - else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING THREE - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); - boltBool = true; - } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ //TOUCHING FOUR - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); - //boltBool = true; - } - else{ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.6, 0, true, false); - boltBool = true; - } - - if (boltBool) drawBolt(r, c); - } - - function drawBolt(r, c){ - context.strokeStyle = spikeColors[3]; - context.beginPath(); - context.arc(c*tileSize+(tileSize*.55), r*tileSize+(tileSize*.45), 4, -.7*Math.PI, .2*Math.PI); - context.lineTo(c*tileSize+(tileSize*.45),r*tileSize+(tileSize*.35)); - context.closePath(); - context.fillStyle = spikeColors[3]; - context.fill(); - context.stroke(); - - context.beginPath(); - context.moveTo(c*tileSize+(tileSize*.43),r*tileSize+(tileSize*.47)); - context.arc(c*tileSize+(tileSize*.48), r*tileSize+(tileSize*.52), 4, .2*Math.PI, -.75*Math.PI); - //context.lineTo(c*tileSize+(tileSize*.4),r*tileSize+(tileSize*.6)); - context.closePath(); - context.fillStyle = spikeColors[3]; - context.fill(); - context.stroke(); - } - - function drawConnector(context, r1, c1, r2, c2, color) { - // either r1 and r2 or c1 and c2 must be equal - if (r1 > r2 || c1 > c2) { - var rTmp = r1; - var cTmp = c1; - r1 = r2; - c1 = c2; - r2 = rTmp; - c2 = cTmp; - } - var xLo = (c1 + 0.4) * tileSize; - var yLo = (r1 + 0.4) * tileSize; - var xHi = (c2 + 0.6) * tileSize; - var yHi = (r2 + 0.6) * tileSize; - context.fillStyle = color; - context.fillRect(xLo, yLo, xHi - xLo, yHi - yLo); - } - function drawBlock(block) { - var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); - var rowcols = block.locations.map(function(location) { - return getRowcol(level, location); - }); - rowcols.forEach(function(rowcol) { - var r = rowcol.r + animationDisplacementRowcol.r; - var c = rowcol.c + animationDisplacementRowcol.c; - context.fillStyle = blockColors[0][block.id % blockColors[0].length]; - drawTileOutlines2(r, c, isAlsoThisBlock, 0.3); - function isAlsoThisBlock(dc, dr) { - for (var i = 0; i < rowcols.length; i++) { - var otherRowcol = rowcols[i]; - if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; - } - return false; - } - }); - } - function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { - var cx = (c + 0.5) * tileSize; - var cy = (r + 0.5) * tileSize; - context.fillStyle = fillStyle; - context.beginPath(); - context.moveTo(cx, cy); - context.arc(cx, cy, radiusFactor * tileSize/2, quadrant * Math.PI/2, (quadrant + 1) * Math.PI/2); - context.fill(); - } - function drawDiamond(r, c, fillStyle) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = fillStyle; - context.beginPath(); - context.moveTo(x + tileSize/2, y); - context.lineTo(x + tileSize, y + tileSize/2); - context.lineTo(x + tileSize/2, y + tileSize); - context.lineTo(x, y + tileSize/2); - context.lineTo(x + tileSize/2, y); - context.fill(); - } - function drawCircle(r, c, radiusFactor, fillStyle) { - context.fillStyle = fillStyle; - context.beginPath(); - context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize/2 * radiusFactor, 0, 2*Math.PI); - context.fill(); - } - function drawRect(r, c, fillStyle) { - context.fillStyle = fillStyle; - context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); - } - - function roundRect(ctx, x, y, width, height, radius, fill, stroke) { //Gooby - if (typeof stroke === 'undefined') { - stroke = true; - } - if (typeof radius === 'undefined') { - radius = 5; - } - if (typeof radius === 'number') { - radius = {tl: radius, tr: radius, br: radius, bl: radius}; - } else { - var defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0}; - for (var side in defaultRadius) { - radius[side] = radius[side] || defaultRadius[side]; - } - } - ctx.beginPath(); - ctx.moveTo(x + radius.tl, y); - ctx.lineTo(x + width - radius.tr, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); - ctx.lineTo(x + width, y + height - radius.br); - ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); - ctx.lineTo(x + radius.bl, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl); - ctx.lineTo(x, y + radius.tl); - ctx.quadraticCurveTo(x, y, x + radius.tl, y); - ctx.closePath(); - if (fill) { - ctx.fill(); - } - if (stroke) { - ctx.stroke(); - } - } - - function drawCloud(c, x, y){ - c.fillStyle = "white"; - c.beginPath(); - c.rect(x, y, tileSize, tileSize); - c.fill(); - c.closePath(); - - c.beginPath(); - c.moveTo(x+tileSize*0, y+tileSize*0); - - c.bezierCurveTo(x+tileSize*0, y-tileSize*.15, x+tileSize*.25, y-tileSize*.15, x+tileSize*.25, y+tileSize*0); - c.bezierCurveTo(x+tileSize*.25, y-tileSize*.15, x+tileSize*.5, y-tileSize*.15, x+tileSize*.5, y+tileSize*0); - c.bezierCurveTo(x+tileSize*.5, y-tileSize*.15, x+tileSize*.75, y-tileSize*.15, x+tileSize*.75, y+tileSize*0); - c.bezierCurveTo(x+tileSize*.75, y-tileSize*.15, x+tileSize*1, y-tileSize*.15, x+tileSize*1, y+tileSize*0); - - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*0, x+tileSize*1.15, y+tileSize*.25, x+tileSize*1, y+tileSize*.25); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.25, x+tileSize*1.15, y+tileSize*.5, x+tileSize*1, y+tileSize*.5); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.5, x+tileSize*1.15, y+tileSize*.75, x+tileSize*1, y+tileSize*.75); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.75, x+tileSize*1.15, y+tileSize*1, x+tileSize*1, y+tileSize*1); - - c.bezierCurveTo(x+tileSize*1, y+tileSize*1.15, x+tileSize*.75, y+tileSize*1.15, x+tileSize*.75, y+tileSize*1); - c.bezierCurveTo(x+tileSize*.75, y+tileSize*1.15, x+tileSize*.5, y+tileSize*1.15, x+tileSize*.5, y+tileSize*1); - c.bezierCurveTo(x+tileSize*.5, y+tileSize*1.15, x+tileSize*.25, y+tileSize*1.15, x+tileSize*.25, y+tileSize*1); - c.bezierCurveTo(x+tileSize*.25, y+tileSize*1.15, x+tileSize*0, y+tileSize*1.15, x+tileSize*0, y+tileSize*1); - - c.bezierCurveTo(x-tileSize*.15, y+tileSize*1, x-tileSize*.15, y+tileSize*.75, x+tileSize*0, y+tileSize*.75); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*.75, x-tileSize*.15, y+tileSize*.5, x+tileSize*0, y+tileSize*.5); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*.5, x-tileSize*.15, y+tileSize*.25, x+tileSize*0, y+tileSize*.25); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*.25, x-tileSize*.15, y+tileSize*0, x+tileSize*0, y+tileSize*0); - - c.closePath(); - c.fill(); - } - - - function drawR(r,c,fillStyle){ //Gooby - context.fillStyle = fillStyle; - var cornerRadius = 20; - context.lineJoin = "round"; - context.lineWidth = 1; - context.strokeRect(c*tileSize, r*tileSize, tileSize, tileSize); - //context.fillRect(c*tileSize, r*tileSize, tileSize, tileSize); - } - - function drawGrid() { - var buffer = document.createElement("canvas"); - buffer.width = canvas.width; - buffer.height = canvas.height; - var localContext = buffer.getContext("2d"); - - localContext.strokeStyle = "#fff"; - localContext.beginPath(); - for (var r = 0; r < level.height; r++) { - localContext.moveTo(0, tileSize*r); - localContext.lineTo(tileSize*level.width, tileSize*r); - } - for (var c = 0; c < level.width; c++) { - localContext.moveTo(tileSize*c, 0); - localContext.lineTo(tileSize*c, tileSize*level.height); - } - localContext.stroke(); - - context.save(); - context.globalAlpha = 0.4; - context.drawImage(buffer, 0, 0); - context.restore(); - } -} - -function findAnimation(animationTypes, objectId) { - if (animationQueueCursor === animationQueue.length) return null; - var currentAnimation = animationQueue[animationQueueCursor]; - for (var i = 1; i < currentAnimation.length; i++) { - var animation = currentAnimation[i]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === objectId) { - return animation; - } - } -} -function findAnimationDisplacementRowcol(objectType, objectId) { - var dr = 0; - var dc = 0; - var animationTypes = [ - "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK - "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK - ]; - // skip the current one - for (var i = animationQueueCursor + 1; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === objectId) { - dr += animation[2]; - dc += animation[3]; - } - } - } - var movementAnimation = findAnimation(animationTypes, objectId); - if (movementAnimation != null) { - dr += movementAnimation[2] * (1 - animationProgress); - dc += movementAnimation[3] * (1 - animationProgress); - } - return {r: -dr, c: -dc}; -} -function hasFutureRemoveAnimation(object) { - var animationTypes = [ - EXIT_SNAKE, - DIE_BLOCK, - ]; - for (var i = animationQueueCursor; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === object.id) { - return true; - } - } - } -} - -function previewPaste(hoverR, hoverC) { - var offsetR = hoverR - clipboardOffsetRowcol.r; - var offsetC = hoverC - clipboardOffsetRowcol.c; - - var newLevel = JSON.parse(JSON.stringify(level)); - var selectedLocations = []; - var selectedObjects = []; - clipboardData.selectedLocations.forEach(function(location) { - var tileCode = clipboardData.level.map[location]; - var rowcol = getRowcol(clipboardData.level, location); - var r = rowcol.r + offsetR; - var c = rowcol.c + offsetC; - if (!isInBounds(newLevel, r, c)) return; - var newLocation = getLocation(newLevel, r, c); - newLevel.map[newLocation] = tileCode; - selectedLocations.push(newLocation); - }); - clipboardData.selectedObjects.forEach(function(object) { - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(clipboardData.level, object.locations[i]); - rowcol.r += offsetR; - rowcol.c += offsetC; - if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { - // this location is oob - if (object.type === SNAKE) { - // snakes must be completely in bounds - return; - } - // just skip it - continue; - } - var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); - newLocations.push(newLocation); - } - if (newLocations.length === 0) return; // can't have a non-present object - var newObject = JSON.parse(JSON.stringify(object)); - newObject.locations = newLocations; - selectedObjects.push(newObject); - }); - return { - level: newLevel, - selectedLocations: selectedLocations, - selectedObjects: selectedObjects, - }; -} - -function getNaiveOrthogonalPath(a, b) { - // does not include a, but does include b. - var rowcolA = getRowcol(level, a); - var rowcolB = getRowcol(level, b); - var path = []; - if (rowcolA.r < rowcolB.r) { - for (var r = rowcolA.r; r < rowcolB.r; r++) { - path.push(getLocation(level, r + 1, rowcolA.c)); - } - } else { - for (var r = rowcolA.r; r > rowcolB.r; r--) { - path.push(getLocation(level, r - 1, rowcolA.c)); - } - } - if (rowcolA.c < rowcolB.c) { - for (var c = rowcolA.c; c < rowcolB.c; c++) { - path.push(getLocation(level, rowcolB.r, c + 1)); - } - } else { - for (var c = rowcolA.c; c > rowcolB.c; c--) { - path.push(getLocation(level, rowcolB.r, c - 1)); - } - } - return path; -} -function identityFunction(x) { - return x; -} -function compareId(a, b) { - return operatorCompare(a.id, b.id); -} -function operatorCompare(a, b) { - return a < b ? -1 : a > b ? 1 : 0; -} -function clamp(value, min, max) { - if (value < min) return min; - if (value > max) return max; - return value; -} -function copyArray(array) { - return array.map(identityFunction); -} -function getSetIntersection(array1, array2) { - if (array1.length * array2.length === 0) return []; - return array1.filter(function(x) { return array2.indexOf(x) !== -1; }); -} -function makeScaleCoordinatesFunction(width1, width2) { - return function(location) { - return location + (width2 - width1) * Math.floor(location / width1); - }; -} - -var expectHash; -window.addEventListener("hashchange", function() { - if (location.hash === expectHash) { - // We're in the middle of saveLevel() or saveReplay(). - // Don't react to that event. - expectHash = null; - return; - } - // The user typed into the url bar or used Back/Forward browser buttons, etc. - loadFromLocationHash(); -}); -function loadFromLocationHash() { - var hashSegments = location.hash.split("#"); - hashSegments.shift(); // first element is always "" - if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; - var hashPairs = hashSegments.map(function(segment) { - var equalsIndex = segment.indexOf("="); - if (equalsIndex === -1) return ["", segment]; // bad - return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; - }); - - if (hashPairs[0][0] !== "level") return false; - try { - var level = parseLevel(hashPairs[0][1]); - } catch (e) { - alert(e); - return false; - } - loadLevel(level); - if (hashPairs.length > 1) { - try { - if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); - parseAndLoadReplay(hashPairs[1][1]); - } catch (e) { - alert(e); - return false; - } - } - return true; -} - -// run test suite -var testTime = new Date().getTime(); -if (compressSerialization(stringifyLevel(parseLevel(testLevel_v0))) !== testLevel_v0_converted) throw new Error("v0 level conversion is broken"); -// ask the debug console for this variable if you're concerned with how much time this wastes. -testTime = new Date().getTime() - testTime; - -loadPersistentState(); -if (!loadFromLocationHash()) { - loadLevel(parseLevel(exampleLevel)); -} From 32791657ff90bbd7ec90a3734401735b5b3fd707 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:25:11 -0500 Subject: [PATCH 193/577] Delete Patashu.js --- Patashu.js | 2677 ---------------------------------------------------- 1 file changed, 2677 deletions(-) delete mode 100644 Patashu.js diff --git a/Patashu.js b/Patashu.js deleted file mode 100644 index c97a6b79..00000000 --- a/Patashu.js +++ /dev/null @@ -1,2677 +0,0 @@ -if (typeof VERSION !== "undefined") { - document.getElementById("versionSpan").innerHTML = - '' + VERSION + ''; -} -var canvas = document.getElementById("canvas"); - -var SPACE = "0".charCodeAt(0); -var WALL = "1".charCodeAt(0); -var SPIKE = "2".charCodeAt(0); -var FRUIT = "3".charCodeAt(0); -var EXIT = "4".charCodeAt(0); -var PORTAL = "5".charCodeAt(0); -var WOODPLATFORM = "w".charCodeAt(0); -var ONEWAYWALLU = "u".charCodeAt(0); -var ONEWAYWALLD = "d".charCodeAt(0); -var ONEWAYWALLL = "l".charCodeAt(0); -var ONEWAYWALLR = "r".charCodeAt(0); -var FOAM = "f".charCodeAt(0); -var DIGGABLEDIRT = "t".charCodeAt(0); -var OPENGATE = "o".charCodeAt(0); -var CLOSEDGATE = "c".charCodeAt(0); -var validTileCodes = [SPACE, WALL, SPIKE, FRUIT, EXIT, PORTAL, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, FOAM, DIGGABLEDIRT, OPENGATE, CLOSEDGATE]; - -var tileSize = 30; -var level; -var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; -var uneditStuff = {undoStack:[], redoStack:[], spanId:"editsSpan", undoButtonId:"uneditButton", redoButtonId:"reeditButton"}; -var paradoxes = []; -function loadLevel(newLevel) { - level = newLevel; - - activateAnySnakePlease(); - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - undoStuffChanged(unmoveStuff); - uneditStuff.undoStack = []; - uneditStuff.redoStack = []; - undoStuffChanged(uneditStuff); - render(); -} - - -var magicNumber = "3tFRIoTU"; -var exampleLevel = magicNumber + "&" + - "17&31" + - "?" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000cc0000000000000000" + - "0000000000000oo0000040000000000" + - "00000ww00du00110500000000000000" + - "0000000ftl00011110005fo00000000" + - "000000w0r0u00011000000000000000" + - "000000ww0uu00010003010000000000" + - "0000000000000010100011000300000" + - "0000001111111000110000000110000" + - "0000011111111111111111111110000" + - "0000011111111101111111111100000" + - "0000001111111100111111111100000" + - "0000001111111000111111111100000" + - "/" + - "s0 ?351&350&349/" + - "b0 ?192/"; - -function parseLevel(string) { - // magic number - var cursor = 0; - skipWhitespace(); - if (string.indexOf(magicNumber) !== 0) throw new Error("not a snakefall level"); - cursor += magicNumber.length; - consumeKeyword("&"); - - var level = { - height: -1, - width: -1, - map: [], - objects: [], - }; - - // height, width - level.height = readInt(); - consumeKeyword("&"); - level.width = readInt(); - - // map - var mapData = readRun(); - mapData = decompressSerialization(mapData); - if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); - for (var i = 0; i < mapData.length; i++) { - var tileCode = mapData[i].charCodeAt(0); - if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); - level.map.push(tileCode); - } - - // objects - skipWhitespace(); - while (cursor < string.length) { - var object = { - type: "?", - id: -1, - dead: false, - locations: [], - }; - - // type - object.type = string[cursor]; - var colorArray; - if (object.type === "s") { colorArray = snakeColors; } - else if (object.type === "b") { colorArray = [1]; } - else throw parserError("expected object type code"); - cursor += 1; - - // id - object.id = readInt(); - if (colorArray[object.id % colorArray.length] == null) throw parserError("invalid id"); - - // locations - var locationsData = readRun(); - var locationStrings = locationsData.split("&"); - if (locationStrings.length === 0) throw parserError("locations must be non-empty"); - locationStrings.forEach(function(locationString) { - var location = parseInt(locationString); - if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); - object.locations.push(location); - }); - - level.objects.push(object); - skipWhitespace(); - } - - return level; - - function skipWhitespace() { - while (" \n\t\r".indexOf(string[cursor]) !== -1) { - cursor += 1; - } - } - function consumeKeyword(keyword) { - skipWhitespace(); - if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); - cursor += 1; - } - function readInt() { - skipWhitespace(); - for (var i = cursor; i < string.length; i++) { - if ("0123456789".indexOf(string[i]) === -1) break; - } - var substring = string.substring(cursor, i); - if (substring.length === 0) throw parserError("expected int"); - cursor = i; - return parseInt(substring, 10); - } - function readRun() { - consumeKeyword("?"); - var endIndex = string.indexOf("/", cursor); - var substring = string.substring(cursor, endIndex); - cursor = endIndex + 1; - return substring; - } - function parserError(message) { - return new Error("parse error at position " + cursor + ": " + message); - } -} - -function serializeTileCode(tileCode) { - return String.fromCharCode(tileCode); -} - -function stringifyLevel(level) { - var output = magicNumber + "&"; - output += level.height + "&" + level.width + "\n"; - - output += "?\n"; - for (var r = 0; r < level.height; r++) { - output += " " + level.map.slice(r * level.width, (r + 1) * level.width).map(serializeTileCode).join("") + "\n"; - } - output += "/\n"; - - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - output += object.type + object.id + " "; - output += "?" + object.locations.join("&") + "/\n"; - } - - // sanity check - var shouldBeTheSame = parseLevel(output); - if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken - - return output; -} -function serializeObjectState(object) { - if (object == null) return [0,[]]; - return [object.dead, copyArray(object.locations)]; -} - -var base66 = "----0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -function compressSerialization(string) { - string = string.replace(/\s+/g, ""); - // run-length encode several 0's in a row, etc. - // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) - var result = ""; - var runStart = 0; - for (var i = 1; i < string.length + 1; i++) { - var runLength = i - runStart; - if (string[i] === string[runStart] && runLength < base66.length - 1) continue; - // end of run - if (runLength >= 4) { - // compress - result += "*" + base66[runLength] + string[runStart]; - } else { - // literal - result += string.substring(runStart, i); - } - runStart = i; - } - return result; -} -function decompressSerialization(string) { - string = string.replace(/\s+/g, ""); - var result = ""; - for (var i = 0; i < string.length; i++) { - if (string[i] === "*") { - i += 1; - var runLength = base66.indexOf(string[i]); - i += 1; - var char = string[i]; - for (var j = 0; j < runLength; j++) { - result += char; - } - } else { - result += string[i]; - } - } - return result; -} - -function stringifyReplay() { - throw asdf; // TODO -} -function parseAndLoadReplay(string) { - throw asdf; // TODO -} - -function saveToUrlBar(withReplay) { - var hash = "#level=" + compressSerialization(stringifyLevel(level)); - if (withReplay) { - hash += "#replay=" + stringifyReplay(); - } - location.hash = hash; -} - -function deepEquals(a, b) { - if (a == null) return b == null; - if (typeof a === "string" || typeof a === "number") return a === b; - if (Array.isArray(a)) { - if (!Array.isArray(b)) return false; - if (a.length !== b.length) return false; - for (var i = 0; i < a.length; i++) { - if (!deepEquals(a[i], b[i])) return false; - } - return true; - } - // must be objects - var aKeys = Object.keys(a); - var bKeys = Object.keys(b); - if (aKeys.length !== bKeys.length) return false; - aKeys.sort(); - bKeys.sort(); - if (!deepEquals(aKeys, bKeys)) return false; - for (var i = 0; i < aKeys.length; i++) { - if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; - } - return true; -} - -function getLocation(level, r, c) { - if (!isInBounds(level, r, c)) throw asdf; - return r * level.width + c; -} -function getRowcol(level, location) { - if (location < 0 || location >= level.width * level.height) throw asdf; - var r = Math.floor(location / level.width); - var c = location % level.width; - return {r:r, c:c}; -} -function isInBounds(level, r, c) { - if (c < 0 || c >= level.width) return false;; - if (r < 0 || r >= level.height) return false;; - return true; -} -function offsetLocation(location, dr, dc) { - var rowcol = getRowcol(level, location); - return getLocation(level, rowcol.r + dr, rowcol.c + dc); -} - -var SHIFT = 1; -var CTRL = 2; -var ALT = 4; -document.addEventListener("keydown", function(event) { - var modifierMask = ( - (event.shiftKey ? SHIFT : 0) | - (event.ctrlKey ? CTRL : 0) | - (event.altKey ? ALT : 0) - ); - switch (event.keyCode) { - case 37: // left - if (modifierMask === 0) { move(0, -1); break; } - return; - case 38: // up - if (modifierMask === 0) { move(-1, 0); break; } - return; - case 39: // right - if (modifierMask === 0) { move(0, 1); break; } - return; - case 40: // down - if (modifierMask === 0) { move(1, 0); break; } - return; - case 8: // backspace - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Q".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Z".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { undo(uneditStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL|SHIFT) { redo(uneditStuff); break; } - return; - case "Y".charCodeAt(0): - if (modifierMask === 0) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { redo(uneditStuff); break; } - return; - case "R".charCodeAt(0): - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } - if (modifierMask === 0) { reset(unmoveStuff); break; } - if (modifierMask === SHIFT) { replay(unmoveStuff); break; } - return; - - case "P".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { playtest(); break; } - return; - case 220: // backslash - if (modifierMask === 0) { toggleShowEditor(); break; } - return; - case "A".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, -1); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PORTAL); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { selectAll(); break; } - return; - case "E".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - return; - case 46: // delete - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - return; - case "W".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } - return; - case "S".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPIKE); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } - if (modifierMask === CTRL ) { saveToUrlBar(); break; } - if (modifierMask === (CTRL|SHIFT)) { saveToUrlBar(true); break; } - return; - case "X".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(EXIT); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } - return; - case "F".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } - return; - case "D".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode("s"); break; } - return; - case "B".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode("b"); break; } - return; - case "G".charCodeAt(0): - if (modifierMask === 0) { toggleGrid(); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } - return; - case "C".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === SHIFT) { toggleCollision(); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } - return; - case "V".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } - return; - case 32: // spacebar - case 9: // tab - if (modifierMask === 0) { switchSnakes( 1); break; } - if (modifierMask === SHIFT) { switchSnakes(-1); break; } - return; - case "1".charCodeAt(0): - case "2".charCodeAt(0): - case "3".charCodeAt(0): - case "4".charCodeAt(0): - var index = event.keyCode - "1".charCodeAt(0); - var delta; - if (modifierMask === 0) { - delta = 1; - } else if (modifierMask === SHIFT) { - delta = -1; - } else return; - if (isAlive()) { - (function() { - var snakes = findSnakesOfColor(index); - if (snakes.length === 0) return; - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; - } - } - activeSnakeId = snakes[0].id; - })(); - } - break; - case 27: // escape - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(null); break; } - return; - default: return; - } - event.preventDefault(); - render(); -}); - -document.getElementById("switchSnakesButton").addEventListener("click", function() { - switchSnakes(1); - render(); -}); -function switchSnakes(delta) { - if (!isAlive()) return; - var snakes = getSnakes(); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; - } - } - activeSnakeId = snakes[0].id; -} -document.getElementById("showGridButton").addEventListener("click", function() { - toggleGrid(); -}); -document.getElementById("saveProgressButton").addEventListener("click", function() { - saveToUrlBar(true); -}); -document.getElementById("restartButton").addEventListener("click", function() { - reset(unmoveStuff); - render(); -}); -document.getElementById("unmoveButton").addEventListener("click", function() { - undo(unmoveStuff); - render(); -}); -document.getElementById("removeButton").addEventListener("click", function() { - redo(unmoveStuff); - render(); -}); - -document.getElementById("showHideEditor").addEventListener("click", function() { - toggleShowEditor(); -}); -function toggleShowEditor() { - persistentState.showEditor = !persistentState.showEditor; - savePersistentState(); - showEditorChanged(); -} -function toggleGrid() { - persistentState.showGrid = !persistentState.showGrid; - savePersistentState(); - render(); -} -["serializationTextarea", "shareLinkTextbox"].forEach(function(id) { - document.getElementById(id).addEventListener("keydown", function(event) { - // let things work normally - event.stopPropagation(); - }); -}); -document.getElementById("submitSerializationButton").addEventListener("click", function() { - var string = document.getElementById("serializationTextarea").value; - try { - var newLevel = parseLevel(string); - } catch (e) { - alert(e); - return; - } - loadLevel(newLevel); -}); -document.getElementById("shareLinkTextbox").addEventListener("focus", function() { - setTimeout(function() { - document.getElementById("shareLinkTextbox").select(); - }, 0); -}); - -var paintBrushTileCode = null; -var paintBrushSnakeColorIndex = 0; -var paintBrushBlockId = 0; -var paintBrushObject = null; -var selectionStart = null; -var selectionEnd = null; -var resizeDragAnchorRowcol = null; -var clipboardData = null; -var clipboardOffsetRowcol = null; -var paintButtonIdAndTileCodes = [ - ["resizeButton", "resize"], - ["selectButton", "select"], - ["pasteButton", "paste"], - ["paintSpaceButton", SPACE], - ["paintWallButton", WALL], - ["paintSpikeButton", SPIKE], - ["paintExitButton", EXIT], - ["paintFruitButton", FRUIT], - ["paintPortalButton", PORTAL], - ["paintWoodPlatformButton", WOODPLATFORM], - ["paintOneWayWallUButton", ONEWAYWALLU], - ["paintOneWayWallDButton", ONEWAYWALLD], - ["paintOneWayWallLButton", ONEWAYWALLL], - ["paintOneWayWallRButton", ONEWAYWALLR], - ["paintFoamButton", FOAM], - ["paintDiggableDirtButton", DIGGABLEDIRT], - ["paintOpenGateButton", OPENGATE], - ["paintClosedGateButton", CLOSEDGATE], - ["paintSnakeButton", "s"], - ["paintBlockButton", "b"], -]; -paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - document.getElementById(id).addEventListener("click", function() { - setPaintBrushTileCode(tileCode); - }); -}); -document.getElementById("playtestButton").addEventListener("click", function() { - playtest(); -}); -document.getElementById("uneditButton").addEventListener("click", function() { - undo(uneditStuff); - render(); -}); -document.getElementById("reeditButton").addEventListener("click", function() { - redo(uneditStuff); - render(); -}); -document.getElementById("saveLevelButton").addEventListener("click", function() { - saveToUrlBar(); -}); -document.getElementById("copyButton").addEventListener("click", function() { - copySelection(); -}); -document.getElementById("cutButton").addEventListener("click", function() { - cutSelection(); -}); -document.getElementById("cheatGravityButton").addEventListener("click", function() { - toggleGravity(); -}); -document.getElementById("cheatCollisionButton").addEventListener("click", function() { - toggleCollision(); -}); -function toggleGravity() { - isGravityEnabled = !isGravityEnabled; - isCollisionEnabled = true; - refreshCheatButtonText(); -} -function toggleCollision() { - isCollisionEnabled = !isCollisionEnabled; - isGravityEnabled = false; - refreshCheatButtonText(); -} -function refreshCheatButtonText() { - document.getElementById("cheatGravityButton").value = isGravityEnabled ? "Gravity: ON" : "Gravity: OFF"; - document.getElementById("cheatGravityButton").style.background = isGravityEnabled ? "" : "#f88"; - - document.getElementById("cheatCollisionButton").value = isCollisionEnabled ? "Collision: ON" : "Collision: OFF"; - document.getElementById("cheatCollisionButton").style.background = isCollisionEnabled ? "" : "#f88"; -} - -// be careful with location vs rowcol, because this variable is used when resizing -var lastDraggingRowcol = null; -var hoverLocation = null; -var draggingChangeLog = null; -canvas.addEventListener("mousedown", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - var location = getLocationFromEvent(event); - if (persistentState.showEditor && paintBrushTileCode != null) { - // editor tool - lastDraggingRowcol = getRowcol(level, location); - if (paintBrushTileCode === "select") selectionStart = location; - if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; - draggingChangeLog = []; - paintAtLocation(location, draggingChangeLog); - } else { - // playtime - var object = findObjectAtLocation(location); - if (object == null) return; - if (object.type !== "s") return; - // active snake - activeSnakeId = object.id; - render(); - } -}); -canvas.addEventListener("dblclick", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - if (persistentState.showEditor && paintBrushTileCode === "select") { - // double click with select tool - var location = getLocationFromEvent(event); - var object = findObjectAtLocation(location); - if (object == null) return; - stopDragging(); - if (object.type === "s") { - // edit snakes of this color - paintBrushTileCode = "s"; - paintBrushSnakeColorIndex = object.id % snakeColors.length; - } else if (object.type === "b") { - // edit this particular block - paintBrushTileCode = "b"; - paintBrushBlockId = object.id; - } else throw asdf; - paintBrushTileCodeChanged(); - } -}); -document.addEventListener("mouseup", function(event) { - stopDragging(); -}); -function stopDragging() { - if (lastDraggingRowcol != null) { - // release the draggin' - lastDraggingRowcol = null; - paintBrushObject = null; - resizeDragAnchorRowcol = null; - pushUndo(uneditStuff, draggingChangeLog); - draggingChangeLog = null; - } -} -canvas.addEventListener("mousemove", function(event) { - if (!persistentState.showEditor) return; - var location = getLocationFromEvent(event); - var mouseRowcol = getRowcol(level, location); - if (lastDraggingRowcol != null) { - // Dragging Force - Through the Fruit and Flames - var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); - // we need to get rowcols for everything before we start dragging, because dragging might resize the world. - var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function(location) { - return getRowcol(level, location); - }); - path.forEach(function(rowcol) { - // convert to location at the last minute in case each of these steps is changing the coordinate system. - paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); - }); - lastDraggingRowcol = mouseRowcol; - hoverLocation = null; - } else { - // hovering - if (hoverLocation !== location) { - hoverLocation = location; - render(); - } - } -}); -canvas.addEventListener("mouseout", function() { - if (hoverLocation !== location) { - // turn off the hover when the mouse leaves - hoverLocation = null; - render(); - } -}); -function getLocationFromEvent(event) { - var r = Math.floor(eventToMouseY(event, canvas) / tileSize); - var c = Math.floor(eventToMouseX(event, canvas) / tileSize); - return getLocation(level, r, c); -} -function eventToMouseX(event, canvas) { return event.clientX - canvas.getBoundingClientRect().left; } -function eventToMouseY(event, canvas) { return event.clientY - canvas.getBoundingClientRect().top; } - -function selectAll() { - selectionStart = 0; - selectionEnd = level.map.length - 1; - setPaintBrushTileCode("select"); -} - -function setPaintBrushTileCode(tileCode) { - if (tileCode === "paste") { - // make sure we have something to paste - if (clipboardData == null) return; - } - if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { - // usually this means to fill in the selection - if (tileCode == null) { - // cancel selection - selectionStart = null; - selectionEnd = null; - return; - } - if (typeof tileCode === "number" && tileCode !== PORTAL) { - // fill in the selection - fillSelection(tileCode); - selectionStart = null; - selectionEnd = null; - return; - } - // ok, just select something else then. - selectionStart = null; - selectionEnd = null; - } - if (tileCode === "s") { - if (paintBrushTileCode === "s") { - // next snake color - paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; - } - } else if (tileCode === "b") { - var blocks = getBlocks(); - if (paintBrushTileCode === "b" && blocks.length > 0) { - // cycle through block ids - blocks.sort(compareId); - if (paintBrushBlockId != null) { - (function() { - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id === paintBrushBlockId) { - i += 1; - if (i < blocks.length) { - // next block id - paintBrushBlockId = blocks[i].id; - } else { - // new block id - paintBrushBlockId = null; - } - return; - } - } - throw asdf - })(); - } else { - // first one - paintBrushBlockId = blocks[0].id; - } - } else { - // new block id - paintBrushBlockId = null; - } - } else if (tileCode == null) { - // escape - if (paintBrushTileCode === "b" && paintBrushBlockId != null) { - // stop editing this block, but keep the block brush selected - tileCode = "b"; - paintBrushBlockId = null; - } - } - paintBrushTileCode = tileCode; - paintBrushTileCodeChanged(); -} -function paintBrushTileCodeChanged() { - paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - var backgroundStyle = ""; - if (tileCode === paintBrushTileCode) { - if (tileCode === "s") { - backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; - } else { - backgroundStyle = "#ff0"; - } - } - document.getElementById(id).style.background = backgroundStyle; - }); - - var isSelectionMode = paintBrushTileCode === "select"; - ["cutButton", "copyButton"].forEach(function (id) { - document.getElementById(id).disabled = !isSelectionMode; - }); - document.getElementById("pasteButton").disabled = clipboardData == null; - - render(); -} - -function cutSelection() { - copySelection(); - fillSelection(SPACE); - render(); -} -function copySelection() { - var selectedLocations = getSelectedLocations(); - if (selectedLocations.length === 0) return; - var selectedObjects = []; - selectedLocations.forEach(function(location) { - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(selectedObjects, object); - }); - setClipboardData({ - level: JSON.parse(JSON.stringify(level)), - selectedLocations: selectedLocations, - selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), - }); -} -function setClipboardData(data) { - // find the center - var minR = Infinity; - var maxR = -Infinity; - var minC = Infinity; - var maxC = -Infinity; - data.selectedLocations.forEach(function(location) { - var rowcol = getRowcol(data.level, location); - if (rowcol.r < minR) minR = rowcol.r; - if (rowcol.r > maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var offsetR = Math.floor((minR + maxR) / 2); - var offsetC = Math.floor((minC + maxC) / 2); - - clipboardData = data; - clipboardOffsetRowcol = {r:offsetR, c:offsetC}; - paintBrushTileCodeChanged(); -} -function fillSelection(tileCode) { - var changeLog = []; - var locations = getSelectedLocations(); - locations.forEach(function(location) { - if (level.map[location] !== tileCode) { - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; - } - removeAnyObjectAtLocation(location, changeLog); - }); - pushUndo(uneditStuff, changeLog); -} -function getSelectedLocations() { - if (selectionStart == null || selectionEnd == null) return []; - var rowcol1 = getRowcol(level, selectionStart); - var rowcol2 = getRowcol(level, selectionEnd); - var r1 = rowcol1.r; - var c1 = rowcol1.c; - var r2 = rowcol2.r; - var c2 = rowcol2.c; - if (r2 < r1) { - var tmp = r1; - r1 = r2; - r2 = tmp; - } - if (c2 < c1) { - var tmp = c1; - c1 = c2; - c2 = tmp; - } - var objects = []; - var locations = []; - for (var r = r1; r <= r2; r++) { - for (var c = c1; c <= c2; c++) { - var location = getLocation(level, r, c); - locations.push(location); - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(objects, object); - } - } - // select the rest of any partially-selected objects - objects.forEach(function(object) { - object.locations.forEach(function(location) { - addIfNotPresent(locations, location); - }); - }); - return locations; -} - -function setHeight(newHeight, changeLog) { - if (newHeight < level.height) { - // crop - for (var r = newHeight; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - // also delete non-space tiles - paintTileAtLocation(location, SPACE, changeLog); - } - } - level.map.splice(newHeight * level.width); - } else { - // expand - for (var r = level.height; r < newHeight; r++) { - for (var c = 0; c < level.width; c++) { - level.map.push(SPACE); - } - } - } - changeLog.push(["h", level.height, newHeight]); - level.height = newHeight; -} -function setWidth(newWidth, changeLog) { - if (newWidth < level.width) { - // crop - for (var r = level.height - 1; r >= 0; r--) { - for (var c = level.width - 1; c >= newWidth; c--) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, SPACE, changeLog); - level.map.splice(location, 1); - } - } - } else { - // expand - for (var r = level.height - 1; r >= 0; r--) { - var insertionPoint = level.width * (r + 1); - for (var c = level.width; c < newWidth; c++) { - // boy is this inefficient. ... YOLO! - level.map.splice(insertionPoint, 0, SPACE); - } - } - } - - var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); - level.objects.forEach(function(object) { - object.locations = object.locations.map(transformLocation); - }); - - changeLog.push(["w", level.width, newWidth]); - level.width = newWidth; -} - -function newSnake(color, location) { - var snakes = findSnakesOfColor(color); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id !== i * snakeColors.length + color) break; - } - return { - type: "s", - id: i * snakeColors.length + color, - dead: false, - locations: [location], - }; -} -function newBlock(location) { - var blocks = getBlocks(); - blocks.sort(compareId); - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id !== i) break; - } - return { - type: "b", - id: i, - dead: false, // unused - locations: [location], - }; -} -function paintAtLocation(location, changeLog) { - if (typeof paintBrushTileCode === "number") { - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, paintBrushTileCode, changeLog); - } else if (paintBrushTileCode === "resize") { - var toRowcol = getRowcol(level, location); - var dr = toRowcol.r - resizeDragAnchorRowcol.r; - var dc = toRowcol.c - resizeDragAnchorRowcol.c; - resizeDragAnchorRowcol = toRowcol; - if (dr !== 0) setHeight(level.height + dr, changeLog); - if (dc !== 0) setWidth(level.width + dc, changeLog); - } else if (paintBrushTileCode === "select") { - selectionEnd = location; - } else if (paintBrushTileCode === "paste") { - var hoverRowcol = getRowcol(level, location); - var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); - pastedData.selectedLocations.forEach(function(location) { - var tileCode = pastedData.level.map[location]; - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, tileCode, changeLog); - }); - pastedData.selectedObjects.forEach(function(object) { - // refresh the ids so there are no collisions. - if (object.type === "s") { - object.id = newSnake(object.id % snakeColors.length).id; - } else if (object.type === "b") { - object.id = newBlock().id; - } else throw asdf; - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - }); - } else if (paintBrushTileCode === "s") { - var oldSnakeSerialization = serializeObjectState(paintBrushObject); - if (paintBrushObject != null) { - // keep dragging - if (paintBrushObject.locations[0] === location) return; // we just did that - // watch out for self-intersection - var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); - if (selfIntersectionIndex !== -1) { - // truncate from here back - paintBrushObject.locations.splice(selfIntersectionIndex); - } - } - - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - if (paintBrushObject == null) { - var thereWereNoSnakes = countSnakes() === 0; - paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); - level.objects.push(paintBrushObject); - if (thereWereNoSnakes) activateAnySnakePlease(); - } else { - // extend le snake - paintBrushObject.locations.unshift(location); - } - changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); - } else if (paintBrushTileCode === "b") { - var objectHere = findObjectAtLocation(location); - if (paintBrushBlockId == null && objectHere != null && objectHere.type === "b") { - // just start editing this block - paintBrushBlockId = objectHere.id; - } else { - // make a change - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - var thisBlock = null; - if (paintBrushBlockId != null) { - thisBlock = findBlockById(paintBrushBlockId); - } - var oldBlockSerialization = serializeObjectState(thisBlock); - if (thisBlock == null) { - // create new block - removeAnyObjectAtLocation(location, changeLog); - thisBlock = newBlock(location); - level.objects.push(thisBlock); - paintBrushBlockId = thisBlock.id; - } else { - var existingIndex = thisBlock.locations.indexOf(location); - if (existingIndex !== -1) { - // reclicking part of this object means to delete just part of it. - if (thisBlock.locations.length === 1) { - // goodbye - removeObject(thisBlock, changeLog); - paintBrushBlockId = null; - } else { - thisBlock.locations.splice(existingIndex, 1); - } - } else { - // add a tile to the block - removeAnyObjectAtLocation(location, changeLog); - thisBlock.locations.push(location); - } - } - changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); - } - } else throw asdf; - render(); -} - -function paintTileAtLocation(location, tileCode, changeLog) { - if (level.map[location] === tileCode) return; - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; -} - -function playtest() { - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - undoStuffChanged(unmoveStuff); -} - -function pushUndo(undoStuff, changeLog) { - // changeLog = [ - // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 - // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] - // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] - // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] - // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. - // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. - // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. - // 10, // the last change is always a declaration of the final width of the map. - // ]; - reduceChangeLog(changeLog); - if (changeLog.length === 0) return; - changeLog.push(level.width); - undoStuff.undoStack.push(changeLog); - undoStuff.redoStack = []; - paradoxes = []; - undoStuffChanged(undoStuff); -} -function reduceChangeLog(changeLog) { - for (var i = 0; i < changeLog.length - 1; i++) { - var change = changeLog[i]; - if (change[0] === "h") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "h") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "w") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "w") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "w") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "h") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "m") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "m" && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (change[2] === change[3]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "s" || change[0] === "b") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === change[0] && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (deepEquals(change[2], change[3])) { - // no change - changeLog.splice(i, 1); - i--; - } - } else throw asdf; - } -} -function undo(undoStuff) { - if (undoStuff.undoStack.length === 0) return; // already at the beginning - animationQueue = []; - paradoxes = []; - undoOneFrame(undoStuff); - undoStuffChanged(undoStuff); -} -function reset(undoStuff) { - animationQueue = []; - paradoxes = []; - while (undoStuff.undoStack.length > 0) { - undoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); -} -function undoOneFrame(undoStuff) { - var doThis = undoStuff.undoStack.pop(); - var redoChangeLog = []; - undoChanges(doThis, redoChangeLog); - if (redoChangeLog.length > 0) { - redoChangeLog.push(level.width); - undoStuff.redoStack.push(redoChangeLog); - } -} -function redo(undoStuff) { - if (undoStuff.redoStack.length === 0) return; // already at the beginning - animationQueue = []; - paradoxes = []; - redoOneFrame(undoStuff); - undoStuffChanged(undoStuff); -} -function replay(undoStuff) { - animationQueue = []; - paradoxes = []; - while (undoStuff.redoStack.length > 0) { - redoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); -} -function redoOneFrame(undoStuff) { - var doThis = undoStuff.redoStack.pop(); - var undoChangeLog = []; - undoChanges(doThis, undoChangeLog); - if (undoChangeLog.length > 0) { - undoChangeLog.push(level.width); - undoStuff.undoStack.push(undoChangeLog); - } -} -function undoChanges(changes, changeLog) { - var widthContext = changes.pop(); - var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); - for (var i = changes.length - 1; i >= 0; i--) { - var paradoxDescription = undoChange(changes[i]); - if (paradoxDescription != null) paradoxes.push(paradoxDescription); - } - - function undoChange(change) { - // note: everything here is going backwards: to -> from - if (change[0] === "h") { - // change height - var fromHeight = change[1]; - var toHeight = change[2]; - if (level.height !== toHeight) return "Impossible"; - setHeight(fromHeight, changeLog); - } else if (change[0] === "w") { - // change width - var fromWidth = change[1]; - var toWidth = change[2]; - if (level.width !== toWidth) return "Impossible"; - setWidth(fromWidth, changeLog); - } else if (change[0] === "m") { - // change map tile - var location = transformLocation(change[1]); - var fromTileCode = change[2]; - var toTileCode = change[3]; - if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; - if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; - paintTileAtLocation(location, fromTileCode, changeLog); - } else if (change[0] === "s" || change[0] === "b") { - // change object - var type = change[0]; - var id = change[1]; - var fromDead = change[2][0]; - var toDead = change[3][0]; - var fromLocations = change[2][1].map(transformLocation); - var toLocations = change[3][1].map(transformLocation); - if (fromLocations.filter(function(location) { return location >= level.map.length; }).length > 0) { - return "Can't move " + describe(type, id) + " out of bounds"; - } - var object = findObjectOfTypeAndId(type, id); - if (toLocations.length !== 0) { - // should exist at this location - if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; - if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; - if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; - // doit - if (fromLocations.length !== 0) { - var oldState = serializeObjectState(object); - object.locations = fromLocations; - object.dead = fromDead; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - } else { - removeObject(object, changeLog); - } - } else { - // shouldn't exist - if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; - // doit - object = { - type: type, - id: id, - dead: fromDead, - locations: fromLocations, - }; - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - } - } else throw asdf; - } -} -function describe(arg1, arg2) { - // describe(0) -> "Space" - // describe("s", 0) -> "Snake 0 (Red)" - // describe(object) -> "Snake 0 (Red)" - // describe("b", 1) -> "Block 1" - if (typeof arg1 === "number") { - switch (arg1) { - case SPACE: return "Space"; - case WALL: return "a Wall"; - case SPIKE: return "Spikes"; - case FRUIT: return "Fruit"; - case EXIT: return "an Exit"; - case PORTAL: return "a Portal"; - case WOODPLATFORM: return "a Wooden Platform"; - case ONEWAYWALLU: return "A One Way Wall (facing U)"; - case ONEWAYWALLD: return "A One Way Wall (facing D)"; - case ONEWAYWALLL: return "A One Way Wall (facing L)"; - case ONEWAYWALLR: return "A One Way Wall (facing R)"; - case FOAM: return "Foam"; - case DIGGABLEDIRT: return "Diggable Dirt"; - case OPENGATE: return "An Open Gate"; - case CLOSEDGATE: return "A Closed Gate"; - default: throw asdf; - } - } - if (arg1 === "s") { - var color = (function() { - switch (snakeColors[arg2 % snakeColors.length]) { - case "#f00": return " (Red)"; - case "#0f0": return " (Green)"; - case "#00f": return " (Blue)"; - case "#ff0": return " (Yellow)"; - case "#f0f": return " (Magenta)"; - case "#0ff": return " (Cyan)"; - case "#80f": return " (Purple)"; - case "#f80": return " (Orange)"; - case "#08f": return " (Azure)"; - case "#d7f": return " (Pink)"; - case "#093": return " (Emerald)"; - case "#932": return " (Brown)"; - default: throw asdf; - } - })(); - return "Snake " + arg2 + color; - } - if (arg1 === "b") { - return "Block " + arg2; - } - if (typeof arg1 === "object") return describe(arg1.type, arg1.id); - throw asdf; -} - -function undoStuffChanged(undoStuff) { - var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; - document.getElementById(undoStuff.spanId).textContent = movesText; - document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; - document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; - - // render paradox display - var uniqueParadoxes = []; - var paradoxCounts = []; - paradoxes.forEach(function(paradoxDescription) { - var index = uniqueParadoxes.indexOf(paradoxDescription); - if (index !== -1) { - paradoxCounts[index] += 1; - } else { - uniqueParadoxes.push(paradoxDescription); - paradoxCounts.push(1); - } - }); - var paradoxDivContent = ""; - uniqueParadoxes.forEach(function(paradox, i) { - if (i > 0) paradoxDivContent += "
    \n"; - if (paradoxCounts[i] > 1) paradoxDivContent += "(" + paradoxCounts[i] + "x) "; - paradoxDivContent += "Time Travel Paradox! " + uniqueParadoxes[i]; - }); - document.getElementById("paradoxDiv").innerHTML = paradoxDivContent; -} - -var persistentState = { - showEditor: false, - showGrid: false, -}; -function savePersistentState() { - localStorage.snakefall = JSON.stringify(persistentState); -} -function loadPersistentState() { - try { - persistentState = JSON.parse(localStorage.snakefall); - } catch (e) { - } - persistentState.showEditor = !!persistentState.showEditor; - persistentState.showGrid = !!persistentState.showGrid; - showEditorChanged(); -} -var isGravityEnabled = true; -function isGravity() { - return isGravityEnabled || !persistentState.showEditor; -} -var isCollisionEnabled = true; -function isCollision() { - return isCollisionEnabled || !persistentState.showEditor; -} -function showEditorChanged() { - document.getElementById("showHideEditor").value = (persistentState.showEditor ? "Hide" : "Show") + " Editor Stuff"; - ["editorDiv", "editorPane"].forEach(function(id) { - document.getElementById(id).style.display = persistentState.showEditor ? "block" : "none"; - }); - document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : "/WASD"; - - render(); -} - -function move(dr, dc) { - animationQueue = []; - freshlyRemovedAnimatedObjects = []; - animationStart = new Date().getTime(); - if (!isAlive()) return; - var changeLog = []; - var activeSnake = findActiveSnake(); - var headRowcol = getRowcol(level, activeSnake.locations[0]); - var newRowcol = {r:headRowcol.r + dr, c:headRowcol.c + dc}; - if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; - var newLocation = getLocation(level, newRowcol.r, newRowcol.c); - - var ate = false; - var pushedObjects = []; - - //track OpenGates that had objects on them - var occupiedOpenGates = getOccupiedOpenGateLocations(); - - if (isCollision()) { - var newTile = level.map[newLocation]; - if (newTile === FRUIT) { - // eat - paintTileAtLocation(newLocation, SPACE, changeLog); - ate = true; - } else if (newTile === DIGGABLEDIRT || newTile === FOAM) { - // dig - paintTileAtLocation(newLocation, SPACE, changeLog); - } - else if (isTileCodeAir(activeSnake, null, newTile, dr, dc)) { - var otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { - if (otherObject === activeSnake) return; // can't push yourself - // push objects - if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; - } - } else return; // can't go through that tile - } - - // slither forward - var activeSnakeOldState = serializeObjectState(activeSnake); - var size1 = activeSnake.locations.length === 1; - var slitherAnimations = [ - 70, - [ - // size-1 snakes really do more of a move than a slither - size1 ? MOVE_SNAKE : SLITHER_HEAD, - activeSnake.id, - dr, - dc, - ] - ]; - activeSnake.locations.unshift(newLocation); - if (!ate) { - // drag your tail forward - var oldRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 1]); - var newRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 2]); - if (!size1) { - slitherAnimations.push([ - SLITHER_TAIL, - activeSnake.id, - newRowcol.r - oldRowcol.r, - newRowcol.c - oldRowcol.c, - ]); - } - activeSnake.locations.pop(); - } - changeLog.push([activeSnake.type, activeSnake.id, activeSnakeOldState, serializeObjectState(activeSnake)]); - - // did you just push your face into a portal? - var portalLocations = getActivePortalLocations(); - var portalActivationLocations = []; - if (portalLocations.indexOf(newLocation) !== -1) { - portalActivationLocations.push(newLocation); - } - // push everything, too - moveObjects(pushedObjects, dr, dc, portalLocations, portalActivationLocations, changeLog, slitherAnimations); - animationQueue.push(slitherAnimations); - - occupiedOpenGates = combineOldAndNewGateOccupations(occupiedOpenGates); - - // gravity loop - if (isGravity()) for (var fallHeight = 1;; fallHeight++) { - // do portals separate from falling logic - if (portalActivationLocations.length === 1) { - var portalAnimations = [500]; - if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { - animationQueue.push(portalAnimations); - } - portalActivationLocations = []; - } - // now do falling logic - var didAnything = false; - var fallingAnimations = [ - 70 / Math.sqrt(fallHeight), - ]; - var exitAnimationQueue = []; - - // check for exit - if (!isUneatenFruit()) { - var snakes = getSnakes(); - for (var i = 0; i < snakes.length; i++) { - var snake = snakes[i]; - if (level.map[snake.locations[0]] === EXIT) { - // (one of) you made it! - removeAnimatedObject(snake, changeLog); - exitAnimationQueue.push([ - 200, - [EXIT_SNAKE, snake.id, 0, 0], - ]); - didAnything = true; - } - } - } - - occupiedOpenGates = combineOldAndNewGateOccupations(occupiedOpenGates); - - // fall - var dyingObjects = []; - var fallingObjects = level.objects.filter(function(object) { - var theseDyingObjects = []; - if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; - // this object can fall. maybe more will fall with it too. we'll check those separately. - theseDyingObjects.forEach(function(object) { - addIfNotPresent(dyingObjects, object); - }); - return true; - }); - if (dyingObjects.length > 0) { - var anySnakesDied = false; - dyingObjects.forEach(function(object) { - if (object.type === "s") { - // look what you've done - var oldState = serializeObjectState(object); - object.dead = true; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - anySnakesDied = true; - } else { - // a box fell off the world - removeAnimatedObject(object, changeLog); - removeFromArray(fallingObjects, object); - exitAnimationQueue.push([ - 200, - [ - DIE_BLOCK, - object.id, - 0, 0 - ], - ]); - didAnything = true; - } - }); - if (anySnakesDied) break; - } - if (fallingObjects.length > 0) { - moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); - didAnything = true; - } - - occupiedOpenGates = closeGates(occupiedOpenGates, changeLog); - - if (!didAnything) break; - Array.prototype.push.apply(animationQueue, exitAnimationQueue); - if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); - } - - pushUndo(unmoveStuff, changeLog); - render(); -} - -function combineOldAndNewGateOccupations(oldOccupiedOpenGates) -{ - var newOccupiedOpenGates = getOccupiedOpenGateLocations(); - var newlyOccupiedOpenGates = getSetSubtract(newOccupiedOpenGates, oldOccupiedOpenGates); - return oldOccupiedOpenGates.concat(newlyOccupiedOpenGates); -} - -function closeGates(oldOccupiedOpenGates, changeLog) -{ - var newOccupiedOpenGates = getOccupiedOpenGateLocations(); - var nowUnoccupiedOpenGates = getSetSubtract(oldOccupiedOpenGates, newOccupiedOpenGates); - for (var i = 0; i < nowUnoccupiedOpenGates.length; i++) { - paintTileAtLocation(nowUnoccupiedOpenGates[i], CLOSEDGATE, changeLog); - } - return newOccupiedOpenGates; -} - -function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects) { - // pusher can be null (for gravity) - pushedObjects.push(pushedObject); - // find forward locations - var forwardLocations = []; - for (var i = 0; i < pushedObjects.length; i++) { - pushedObject = pushedObjects[i]; - for (var j = 0; j < pushedObject.locations.length; j++) { - var rowcol = getRowcol(level, pushedObject.locations[j]); - var forwardRowcol = {r:rowcol.r + dr, c:rowcol.c + dc}; - if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { - if (dyingObjects == null) { - // can't push things out of bounds - return false; - } else { - // this thing is going to fall out of bounds - addIfNotPresent(dyingObjects, pushedObject); - addIfNotPresent(pushedObjects, pushedObject); - continue; - } - } - var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); - var yetAnotherObject = findObjectAtLocation(forwardLocation); - if (yetAnotherObject != null) { - if (yetAnotherObject === pusher) { - // indirect pushing ourselves. - // special check for when we're indirectly pushing the tip of our own tail. - if (forwardLocation === pusher.locations[pusher.locations.length -1]) { - // for some reason this is ok. - continue; - } - return false; - } - addIfNotPresent(pushedObjects, yetAnotherObject); - } - addIfNotPresent(forwardLocations, forwardLocation); - } - } - // check forward locations - for (var i = 0; i < forwardLocations.length; i++) { - var forwardLocation = forwardLocations[i]; - // many of these locations can be inside objects, - // but that means the tile must be air, - // and we already know pushing that object. - var tileCode = level.map[forwardLocation]; - var object = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); - if (!isTileCodeAir(pusher, object, tileCode, dr, dc)) { - if (dyingObjects != null) { - if (tileCode === SPIKE) { - // uh... which object was this again? - if (object.type === "s") { - // ouch! - addIfNotPresent(dyingObjects, object); - continue; - } - } - } - // can't push into something solid - return false; - } - } - // the push is go - return true; -} - -function activateAnySnakePlease() { - var snakes = getSnakes(); - if (snakes.length === 0) return; // nope.avi - activeSnakeId = snakes[0].id; -} - -function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations, changeLog, animations) { - objects.forEach(function(object) { - var oldState = serializeObjectState(object); - var oldPortals = getSetIntersection(portalLocations, object.locations); - for (var i = 0; i < object.locations.length; i++) { - object.locations[i] = offsetLocation(object.locations[i], dr, dc); - if (level.map[object.locations[i]] == FOAM) - { - paintTileAtLocation(object.locations[i], SPACE, changeLog); - } - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - animations.push([ - "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK - object.id, - dr, - dc, - ]); - - var newPortals = getSetIntersection(portalLocations, object.locations); - var activatingPortals = newPortals.filter(function(portalLocation) { - return oldPortals.indexOf(portalLocation) === -1; - }); - if (activatingPortals.length === 1) { - // exactly one new portal we're touching. activate it - portalActivationLocations.push(activatingPortals[0]); - } - }); -} - -function activatePortal(portalLocations, portalLocation, animations, changeLog) { - var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; - var portalRowcol = getRowcol(level, portalLocation); - var otherPortalRowcol = getRowcol(level, otherPortalLocation); - var delta = {r:otherPortalRowcol.r - portalRowcol.r, c:otherPortalRowcol.c - portalRowcol.c}; - - var object = findObjectAtLocation(portalLocation); - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r + delta.r; - var c = rowcol.c + delta.c; - if (!isInBounds(level, r, c)) return false; // out of bounds - newLocations.push(getLocation(level, r, c)); - } - - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return; // blocked by tile - var otherObject = findObjectAtLocation(location); - if (otherObject != null && otherObject !== object) return; // blocked by object - } - - // zappo presto! - var oldState = serializeObjectState(object); - object.locations = newLocations; - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (level.map[location] == FOAM) - { - //dig - paintTileAtLocation(location, SPACE, changeLog); - } - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); -} - -function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { - switch (tileCode) - { - case SPACE: case EXIT: case PORTAL: case OPENGATE: return true; - case WOODPLATFORM: case FOAM: return pusher != null; - case ONEWAYWALLU: return dr != 1; - case ONEWAYWALLD: return dr != -1; - case ONEWAYWALLL: return dc != 1; - case ONEWAYWALLR: return dc != -1; - default: return false; - } -} - -function addIfNotPresent(array, element) { - if (array.indexOf(element) !== -1) return; - array.push(element); -} -function removeAnyObjectAtLocation(location, changeLog) { - var object = findObjectAtLocation(location); - if (object != null) removeObject(object, changeLog); -} -function removeAnimatedObject(object, changeLog) { - removeObject(object, changeLog); - freshlyRemovedAnimatedObjects.push(object); -} -function removeObject(object, changeLog) { - removeFromArray(level.objects, object); - changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0,[]]]); - if (object.type === "s" && object.id === activeSnakeId) { - activateAnySnakePlease(); - } - if (object.type === "b" && paintBrushTileCode === "b" && paintBrushBlockId === object.id) { - // no longer editing an object that doesn't exit - paintBrushBlockId = null; - } -} -function removeFromArray(array, element) { - var index = array.indexOf(element); - if (index === -1) throw asdf; - array.splice(index, 1); -} -function findActiveSnake() { - var snakes = getSnakes(); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) return snakes[i]; - } - throw asdf; -} -function findBlockById(id) { - return findObjectOfTypeAndId("b", id); -} -function findSnakesOfColor(color) { - return level.objects.filter(function(object) { - if (object.type !== "s") return false; - return object.id % snakeColors.length === color; - }); -} -function findObjectOfTypeAndId(type, id) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.type === type && object.id === id) return object; - } - return null; -} -function findObjectAtLocation(location) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.locations.indexOf(location) !== -1) - return object; - } - return null; -} -function isUneatenFruit() { - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === FRUIT) return true; - } - return false; -} -function getActivePortalLocations() { - var portalLocations = getPortalLocations(); - if (portalLocations.length !== 2) return []; // nice try - return portalLocations; -} -function getOccupiedOpenGateLocations() -{ - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === OPENGATE) { - if (findObjectAtLocation(i)) - result.push(i); - } - } - return result; -} -function getPortalLocations() { - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === PORTAL) result.push(i); - } - return result; -} -function countSnakes() { - return getSnakes().length; -} -function getSnakes() { - return getObjectsOfType("s"); -} -function getBlocks() { - return getObjectsOfType("b"); -} -function getObjectsOfType(type) { - return level.objects.filter(function(object) { - return object.type == type; - }); -} -function isDead() { - return getSnakes().filter(function(snake) { - return !!snake.dead; - }).length > 0; -} -function isAlive() { - return countSnakes() > 0 && !isDead(); -} - -var snakeColors = [ - "#f00", - "#0f0", - "#00f", - "#ff0", - "#f0f", - "#0ff", - "#80f", - "#f80", - "#08f", - "#d7f", - "#093", - "#932" -]; -var blockForeground = ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"]; -var blockBackground = ["#853641","#963c84","#753d88","#5d3a96","#3a3990"]; - -var activeSnakeId = null; - -var SLITHER_HEAD = "sh"; -var SLITHER_TAIL = "st"; -var MOVE_SNAKE = "ms"; -var MOVE_BLOCK = "mb"; -var TELEPORT_SNAKE = "ts"; -var TELEPORT_BLOCK = "tb"; -var EXIT_SNAKE = "es"; -var DIE_SNAKE = "ds"; -var DIE_BLOCK = "db"; -var animationQueue = [ - // // sequence of disjoint animation groups. - // // each group completes before the next begins. - // [ - // 70, // duration of this animation group - // // multiple things to animate simultaneously - // [ - // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, - // objectId, - // dr, - // dc, - // ], - // ], -]; -var animationStart = null; // new Date().getTime() -var animationProgress; // 0.0 <= x < 1.0 -var freshlyRemovedAnimatedObjects = []; - -function render() { - if (level == null) return; - if (animationQueue.length > 0) { - var animationDuration = animationQueue[0][0]; - animationProgress = (new Date().getTime() - animationStart) / animationDuration; - if (animationProgress >= 1.0) { - // animation group complete - animationProgress -= 1.0; - animationQueue.shift(); - animationStart = new Date().getTime(); - } - } - if (animationQueue.length === 0) animationProgress = 1.0; - canvas.width = tileSize * level.width; - canvas.height = tileSize * level.height; - var context = canvas.getContext("2d"); - context.fillStyle = "#88f"; // sky - context.fillRect(0, 0, canvas.width, canvas.height); - - if (persistentState.showGrid && !persistentState.showEditor) { - drawGrid(); - } - - var activePortalLocations = getActivePortalLocations(); - - // normal render - renderLevel(); - - if (persistentState.showGrid && persistentState.showEditor) { - drawGrid(); - } - // active snake halo - if (countSnakes() !== 0) { - var activeSnake = findActiveSnake(); - var activeSnakeRowcol = getRowcol(level, activeSnake.locations[0]); - drawCircle(activeSnakeRowcol.r, activeSnakeRowcol.c, 2, "rgba(256,256,256,0.3)"); - } - - if (persistentState.showEditor) { - if (paintBrushTileCode === "b") { - if (paintBrushBlockId != null) { - // fade everything else away - context.fillStyle = "rgba(0, 0, 0, 0.8)"; - context.fillRect(0, 0, canvas.width, canvas.height); - // and render just this object in focus - var activeBlock = findBlockById(paintBrushBlockId); - renderLevel([activeBlock]); - } - } else if (paintBrushTileCode === "select") { - getSelectedLocations().forEach(function(location) { - var rowcol = getRowcol(level, location); - drawRect(rowcol.r, rowcol.c, "rgba(128, 128, 128, 0.3)"); - }); - } - } - - // serialize - var serialization = stringifyLevel(level); - document.getElementById("serializationTextarea").value = serialization; - var link = location.href.substring(0, location.href.length - location.hash.length); - link += "#level=" + compressSerialization(serialization); - document.getElementById("shareLinkTextbox").value = link; - - // throw this in there somewhere - document.getElementById("showGridButton").value = (persistentState.showGrid ? "Hide" : "Show") + " Grid"; - - if (animationProgress < 1.0) requestAnimationFrame(render); - return; // this is the end of the function proper - - function renderLevel(onlyTheseObjects) { - var objects = level.objects; - if (onlyTheseObjects != null) { - objects = onlyTheseObjects; - } else { - objects = level.objects.concat(freshlyRemovedAnimatedObjects.filter(function(object) { - // the object needs to have a future removal animation, or else, it's gone already. - return hasFutureRemoveAnimation(object); - })); - } - // begin by rendering the background connections for blocks - objects.forEach(function(object) { - if (object.type !== "b") return; - var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); - // Make a stencil that excludes the insides of blocks. - // Then when we render the support beams, we won't see the supports inside the block itself. - context.save(); - context.beginPath(); - // Draw a path around the whole screen in the opposite direction as the rectangle paths below. - // This means that the below rectangles will be removing area from the greater rectangle. - context.rect(canvas.width, 0, -canvas.width, canvas.height); - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - rowcol.r += animationDisplacementRowcol.r; - rowcol.c += animationDisplacementRowcol.c; - context.rect(rowcol.c * tileSize, rowcol.r * tileSize, tileSize, tileSize); - } - context.clip(); - for (var i = 0; i < object.locations.length - 1; i++) { - var rowcol1 = getRowcol(level, object.locations[i]); - rowcol1.r += animationDisplacementRowcol.r; - rowcol1.c += animationDisplacementRowcol.c; - var rowcol2 = getRowcol(level, object.locations[i + 1]); - rowcol2.r += animationDisplacementRowcol.r; - rowcol2.c += animationDisplacementRowcol.c; - var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; - drawConnector(rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockBackground[object.id % blockBackground.length]); - drawConnector(rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockBackground[object.id % blockBackground.length]); - } - context.restore(); - }); - - // terrain - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - var tileCode = level.map[location]; - drawTile(tileCode, r, c, level, location); - } - } - } - - // objects - objects.forEach(drawObject); - - // banners - if (countSnakes() === 0) { - context.fillStyle = "#ff0"; - context.font = "100px Arial"; - context.fillText("You Win!", 0, canvas.height / 2); - } - if (isDead()) { - context.fillStyle = "#f00"; - context.font = "100px Arial"; - context.fillText("You Dead!", 0, canvas.height / 2); - } - - // editor hover - if (persistentState.showEditor && paintBrushTileCode != null && hoverLocation != null && hoverLocation < level.map.length) { - - var savedContext = context; - var buffer = document.createElement("canvas"); - buffer.width = canvas.width; - buffer.height = canvas.height; - context = buffer.getContext("2d"); - - var hoverRowcol = getRowcol(level, hoverLocation); - var objectHere = findObjectAtLocation(hoverLocation); - if (typeof paintBrushTileCode === "number") { - if (level.map[hoverLocation] !== paintBrushTileCode) { - drawTile(paintBrushTileCode, hoverRowcol.r, hoverRowcol.c, level, hoverLocation); - } - } else if (paintBrushTileCode === "s") { - if (!(objectHere != null && objectHere.type === "s" && objectHere.id === paintBrushSnakeColorIndex)) { - drawObject(newSnake(paintBrushSnakeColorIndex, hoverLocation)); - } - } else if (paintBrushTileCode === "b") { - if (!(objectHere != null && objectHere.type === "b" && objectHere.id === paintBrushBlockId)) { - drawObject(newBlock(hoverLocation)); - } - } else if (paintBrushTileCode === "resize") { - void 0; // do nothing - } else if (paintBrushTileCode === "select") { - void 0; // do nothing - } else if (paintBrushTileCode === "paste") { - // show what will be pasted if you click - var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); - pastedData.selectedLocations.forEach(function(location) { - var tileCode = pastedData.level.map[location]; - var rowcol = getRowcol(level, location); - drawTile(tileCode, rowcol.r, rowcol.c, pastedData.level, location); - }); - pastedData.selectedObjects.forEach(drawObject); - } else throw asdf; - - context = savedContext; - context.save(); - context.globalAlpha = 0.2; - context.drawImage(buffer, 0, 0); - context.restore(); - } - } - function drawTile(tileCode, r, c, level, location) { - switch (tileCode) { - case SPACE: - break; - case WALL: - drawWall(r, c, getAdjacentTiles()); - break; - case SPIKE: - drawSpikes(r, c, level); - break; - case FRUIT: - drawCircle(r, c, 1, "#f0f"); - break; - case EXIT: - var radiusFactor = isUneatenFruit() ? 0.7 : 1.2; - drawQuarterPie(r, c, radiusFactor, "#f00", 0); - drawQuarterPie(r, c, radiusFactor, "#0f0", 1); - drawQuarterPie(r, c, radiusFactor, "#00f", 2); - drawQuarterPie(r, c, radiusFactor, "#ff0", 3); - break; - case PORTAL: - drawCircle(r, c, 0.8, "#888"); - drawCircle(r, c, 0.6, "#111"); - if (activePortalLocations.indexOf(location) !== -1) drawCircle(r, c, 0.3, "#666"); - break; - case WOODPLATFORM: - drawOneWayWall("#D38345", r, c, -1, 0); - break; - case ONEWAYWALLU: - drawOneWayWall("#BACFD1", r, c, -1, 0); - break; - case ONEWAYWALLD: - drawOneWayWall("#BACFD1", r, c, 1, 0); - break; - case ONEWAYWALLL: - drawOneWayWall("#BACFD1", r, c, 0, -1); - break; - case ONEWAYWALLR: - drawOneWayWall("#BACFD1", r, c, 0, 1); - break; - case FOAM: - drawFoam(r, c); - break; - case DIGGABLEDIRT: - drawDiggableDirt(r, c); - break; - case OPENGATE: - drawGate(r, c, false); - break; - case CLOSEDGATE: - drawGate(r, c, true); - break; - default: throw asdf; - } - function getAdjacentTiles() { - return [ - [getTile(r - 1, c - 1), - getTile(r - 1, c + 0), - getTile(r - 1, c + 1)], - [getTile(r + 0, c - 1), - null, - getTile(r + 0, c + 1)], - [getTile(r + 1, c - 1), - getTile(r + 1, c + 0), - getTile(r + 1, c + 1)], - ]; - } - function getTile(r, c) { - if (!isInBounds(level, r, c)) return null; - return level.map[getLocation(level, r, c)]; - } - } - - function drawObject(object) { - switch (object.type) { - case "s": - var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); - var lastRowcol = null - var color = snakeColors[object.id % snakeColors.length]; - var headRowcol; - for (var i = 0; i <= object.locations.length; i++) { - var animation; - var rowcol; - if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { - // animate head slithering forward - rowcol = getRowcol(level, object.locations[i]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else if (i === object.locations.length) { - // animated tail? - if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { - // animate tail slithering to catch up - rowcol = getRowcol(level, object.locations[i - 1]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else { - // no animated tail needed - break; - } - } else { - rowcol = getRowcol(level, object.locations[i]); - } - if (object.dead) rowcol.r += 0.5; - rowcol.r += animationDisplacementRowcol.r; - rowcol.c += animationDisplacementRowcol.c; - if (i === 0) { - // head - headRowcol = rowcol; - drawDiamond(rowcol.r, rowcol.c, color); - } else { - // middle - var cx = (rowcol.c + 0.5) * tileSize; - var cy = (rowcol.r + 0.5) * tileSize; - context.fillStyle = color; - var orientation; - if (lastRowcol.r < rowcol.r) { - orientation = 0; - context.beginPath(); - context.moveTo((lastRowcol.c + 0) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.lineTo((lastRowcol.c + 1) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.arc(cx, cy, tileSize/2, 0, Math.PI); - context.fill(); - } else if (lastRowcol.r > rowcol.r) { - orientation = 2; - context.beginPath(); - context.moveTo((lastRowcol.c + 1) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.lineTo((lastRowcol.c + 0) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.arc(cx, cy, tileSize/2, Math.PI, 0); - context.fill(); - } else if (lastRowcol.c < rowcol.c) { - orientation = 3; - context.beginPath(); - context.moveTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 1) * tileSize); - context.lineTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 0) * tileSize); - context.arc(cx, cy, tileSize/2, 1.5 * Math.PI, 2.5 * Math.PI); - context.fill(); - } else if (lastRowcol.c > rowcol.c) { - orientation = 1; - context.beginPath(); - context.moveTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 0) * tileSize); - context.lineTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 1) * tileSize); - context.arc(cx, cy, tileSize/2, 2.5 * Math.PI, 1.5 * Math.PI); - context.fill(); - } - } - lastRowcol = rowcol; - } - // eye - if (object.id === activeSnakeId) { - drawCircle(headRowcol.r, headRowcol.c, 0.5, "#fff"); - drawCircle(headRowcol.r, headRowcol.c, 0.2, "#000"); - } - break; - case "b": - drawBlock(object); - break; - default: throw asdf; - } - } - - function drawOneWayWall(fillStyle, r, c, dr, dc) { - context.fillStyle = fillStyle; - if (dr == -1) - { - context.fillRect(c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15); - } - else if (dr == 1) - { - context.fillRect(c * tileSize - tileSize/15, (r + 1) * tileSize - tileSize/15 - tileSize/4, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15); - } - else if (dc == -1) - { - context.fillRect(c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15); - } - else if (dc == 1) - { - context.fillRect((c + 1) * tileSize - tileSize/15 - tileSize/4, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15); - } - - context.lineWidth = 3; - context.strokeStyle = "#777"; - context.beginPath(); - - if (dr == -1) - { - context.moveTo(c * tileSize, r * tileSize + tileSize/2); - context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); - context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); - } - else if (dr == 1) - { - context.moveTo(c * tileSize, r * tileSize + tileSize/2); - context.lineTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); - context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); - } - else if (dc == -1) - { - context.moveTo(c * tileSize + tileSize/2, r * tileSize); - context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); - context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); - } - else if (dc == 1) - { - context.moveTo(c * tileSize + tileSize/2, r * tileSize); - context.lineTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); - context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); - } - - context.stroke(); - context.lineWidth = 0; - } - - function drawFoam(r, c) { - context.fillStyle = "#6BDBC8"; - for (var i = 0; i < 3; i++) { - for (var j = 0; j < 3; j++) { - context.beginPath(); - context.arc(c*tileSize + (i*2+1)*tileSize/6, r*tileSize + (j*2+1)*tileSize/6, tileSize/6, 0, 2*Math.PI); - context.fill(); - } - } - } - - function drawDiggableDirt(r, c) { - drawRect(r, c, "#d37c2a"); - context.fillStyle = "#844204"; - context.beginPath(); - context.moveTo(c*tileSize + tileSize/2, r*tileSize); - context.lineTo((c+1)*tileSize, r*tileSize + tileSize/2); - context.lineTo(c*tileSize + tileSize/2, (r+1)*tileSize); - context.lineTo(c*tileSize, r*tileSize + tileSize/2); - context.lineTo(c*tileSize + tileSize/2, r*tileSize); - context.fill(); - } - - function drawGate(r, c, isClosed) { - if (isClosed) - { - context.lineWidth = 3; - context.strokeStyle = "#444"; - context.beginPath(); - for (var i = 1; i < 3; i++) { - context.beginPath(); - context.moveTo(c*tileSize + i*tileSize/3, r*tileSize); - context.lineTo(c*tileSize + i*tileSize/3, (r+1)*tileSize); - context.stroke(); - } - - for (var i = 1; i < 4; i++) { - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize + i*tileSize/4 + tileSize/15); - context.lineTo((c+1)*tileSize, r*tileSize + i*tileSize/4 + tileSize/15); - context.stroke(); - } - - context.lineWidth = 0; - } - - context.fillStyle = "#777"; - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize); - context.lineTo((c+1)*tileSize, r*tileSize); - context.lineTo((c+1)*tileSize, (r+1)*tileSize); - context.lineTo(c*tileSize + 5*tileSize/6, (r+1)*tileSize); - context.lineTo(c*tileSize + 5*tileSize/6, r*tileSize + tileSize/2); - context.arc(c*tileSize + tileSize/2, r*tileSize + tileSize/2, tileSize/3, 0, Math.PI, true); - context.lineTo(c*tileSize + 1*tileSize/6, (r+1)*tileSize); - context.lineTo(c*tileSize, (r+1)*tileSize); - context.lineTo(c*tileSize, r*tileSize); - context.fill(); - } - - function drawWall(r, c, adjacentTiles) { - drawRect(r, c, "#844204"); // dirt - context.fillStyle = "#282"; // grass - drawTileOutlines(r, c, isWall, 0.2); - - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; - } - } - function drawTileOutlines(r, c, isOccupied, outlineThickness) { - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - var complementPixels = (1 - 2 * outlineThickness) * tileSize; - if (!isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - if (!isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (!isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); - } - function drawSpikes(r, c) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = "#333"; - context.beginPath(); - context.moveTo(x + tileSize * 0.3, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.4, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.5, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.6, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.3); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3); - context.fill(); - } - function drawConnector(r1, c1, r2, c2, color) { - // either r1 and r2 or c1 and c2 must be equal - if (r1 > r2 || c1 > c2) { - var rTmp = r1; - var cTmp = c1; - r1 = r2; - c1 = c2; - r2 = rTmp; - c2 = cTmp; - } - var xLo = (c1 + 0.4) * tileSize; - var yLo = (r1 + 0.4) * tileSize; - var xHi = (c2 + 0.6) * tileSize; - var yHi = (r2 + 0.6) * tileSize; - context.fillStyle = color; - context.fillRect(xLo, yLo, xHi - xLo, yHi - yLo); - } - function drawBlock(block) { - var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); - var rowcols = block.locations.map(function(location) { - return getRowcol(level, location); - }); - rowcols.forEach(function(rowcol) { - var r = rowcol.r + animationDisplacementRowcol.r; - var c = rowcol.c + animationDisplacementRowcol.c; - context.fillStyle = blockForeground[block.id % blockForeground.length]; - drawTileOutlines(r, c, isAlsoThisBlock, 0.3); - function isAlsoThisBlock(dc, dr) { - for (var i = 0; i < rowcols.length; i++) { - var otherRowcol = rowcols[i]; - if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; - } - return false; - } - }); - } - function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { - var cx = (c + 0.5) * tileSize; - var cy = (r + 0.5) * tileSize; - context.fillStyle = fillStyle; - context.beginPath(); - context.moveTo(cx, cy); - context.arc(cx, cy, radiusFactor * tileSize/2, quadrant * Math.PI/2, (quadrant + 1) * Math.PI/2); - context.fill(); - } - function drawDiamond(r, c, fillStyle) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = fillStyle; - context.beginPath(); - context.moveTo(x + tileSize/2, y); - context.lineTo(x + tileSize, y + tileSize/2); - context.lineTo(x + tileSize/2, y + tileSize); - context.lineTo(x, y + tileSize/2); - context.lineTo(x + tileSize/2, y); - context.fill(); - } - function drawCircle(r, c, radiusFactor, fillStyle) { - context.fillStyle = fillStyle; - context.beginPath(); - context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize/2 * radiusFactor, 0, 2*Math.PI); - context.fill(); - } - function drawRect(r, c, fillStyle) { - context.fillStyle = fillStyle; - context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); - } - - function drawGrid() { - var buffer = document.createElement("canvas"); - buffer.width = canvas.width; - buffer.height = canvas.height; - var localContext = buffer.getContext("2d"); - - localContext.strokeStyle = "#fff"; - localContext.beginPath(); - for (var r = 0; r < level.height; r++) { - localContext.moveTo(0, tileSize*r); - localContext.lineTo(tileSize*level.width, tileSize*r); - } - for (var c = 0; c < level.width; c++) { - localContext.moveTo(tileSize*c, 0); - localContext.lineTo(tileSize*c, tileSize*level.height); - } - localContext.stroke(); - - context.save(); - context.globalAlpha = 0.4; - context.drawImage(buffer, 0, 0); - context.restore(); - } -} - -function findAnimation(animationTypes, objectId) { - if (animationQueue.length === 0) return null; - var currentAnimation = animationQueue[0]; - for (var i = 1; i < currentAnimation.length; i++) { - var animation = currentAnimation[i]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === objectId) { - return animation; - } - } -} -function findAnimationDisplacementRowcol(objectType, objectId) { - var dr = 0; - var dc = 0; - var animationTypes = [ - "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK - "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK - ]; - // skip the current one - for (var i = 1; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === objectId) { - dr += animation[2]; - dc += animation[3]; - } - } - } - var movementAnimation = findAnimation(animationTypes, objectId); - if (movementAnimation != null) { - dr += movementAnimation[2] * (1 - animationProgress); - dc += movementAnimation[3] * (1 - animationProgress); - } - return {r: -dr, c: -dc}; -} -function hasFutureRemoveAnimation(object) { - var animationTypes = [ - EXIT_SNAKE, - DIE_BLOCK, - ]; - for (var i = 0; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === object.id) { - return true; - } - } - } -} - -function previewPaste(hoverR, hoverC) { - var offsetR = hoverR - clipboardOffsetRowcol.r; - var offsetC = hoverC - clipboardOffsetRowcol.c; - - var newLevel = JSON.parse(JSON.stringify(level)); - var selectedLocations = []; - var selectedObjects = []; - clipboardData.selectedLocations.forEach(function(location) { - var tileCode = clipboardData.level.map[location]; - var rowcol = getRowcol(clipboardData.level, location); - var r = rowcol.r + offsetR; - var c = rowcol.c + offsetC; - if (!isInBounds(newLevel, r, c)) return; - var newLocation = getLocation(newLevel, r, c); - newLevel.map[newLocation] = tileCode; - selectedLocations.push(newLocation); - }); - clipboardData.selectedObjects.forEach(function(object) { - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(clipboardData.level, object.locations[i]); - rowcol.r += offsetR; - rowcol.c += offsetC; - if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { - // this location is oob - if (object.type === "s") { - // snakes must be completely in bounds - return; - } - // just skip it - continue; - } - var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); - newLocations.push(newLocation); - } - if (newLocations.length === 0) return; // can't have a non-present object - var newObject = JSON.parse(JSON.stringify(object)); - newObject.locations = newLocations; - selectedObjects.push(newObject); - }); - return { - level: newLevel, - selectedLocations: selectedLocations, - selectedObjects: selectedObjects, - }; -} - -function getNaiveOrthogonalPath(a, b) { - // does not include a, but does include b. - var rowcolA = getRowcol(level, a); - var rowcolB = getRowcol(level, b); - var path = []; - if (rowcolA.r < rowcolB.r) { - for (var r = rowcolA.r; r < rowcolB.r; r++) { - path.push(getLocation(level, r + 1, rowcolA.c)); - } - } else { - for (var r = rowcolA.r; r > rowcolB.r; r--) { - path.push(getLocation(level, r - 1, rowcolA.c)); - } - } - if (rowcolA.c < rowcolB.c) { - for (var c = rowcolA.c; c < rowcolB.c; c++) { - path.push(getLocation(level, rowcolB.r, c + 1)); - } - } else { - for (var c = rowcolA.c; c > rowcolB.c; c--) { - path.push(getLocation(level, rowcolB.r, c - 1)); - } - } - return path; -} -function identityFunction(x) { - return x; -} -function compareId(a, b) { - return operatorCompare(a.id, b.id); -} -function operatorCompare(a, b) { - return a < b ? -1 : a > b ? 1 : 0; -} -function copyArray(array) { - return array.map(identityFunction); -} -function getSetIntersection(array1, array2) { - if (array1.length * array2.length === 0) return []; - return array1.filter(function(x) { return array2.indexOf(x) !== -1; }); -} -function getSetSubtract(array1, array2) { - if (array1.length === 0) return []; - return array1.filter(function(x) { return array2.indexOf(x) == -1; }); -} -function makeScaleCoordinatesFunction(width1, width2) { - return function(location) { - return location + (width2 - width1) * Math.floor(location / width1); - }; -} - -window.addEventListener("hashchange", function() { - loadFromLocationHash(); -}); -function loadFromLocationHash() { - var hashSegments = location.hash.split("#"); - hashSegments.shift(); // first element is always "" - if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; - var hashPairs = hashSegments.map(function(segment) { - var equalsIndex = segment.indexOf("="); - if (equalsIndex === -1) return ["", segment]; // bad - return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; - }); - - if (hashPairs[0][0] !== "level") return false; - try { - var level = parseLevel(hashPairs[0][1]); - } catch (e) { - alert(e); - return false; - } - if (hashPairs.length > 1) { - if (hashPairs[1][0] !== "replay") return false; - if (!parseAndLoadReplay(hashPairs[1][1])) return false; - } - loadLevel(level); - return true; -} - -loadPersistentState(); -if (!loadFromLocationHash()) { - loadLevel(parseLevel(exampleLevel)); -} From c721d50349db852d9f6b707707d236f048f49911 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:25:12 -0500 Subject: [PATCH 194/577] Delete _config.yml --- _config.yml | 1 - 1 file changed, 1 deletion(-) delete mode 100644 _config.yml diff --git a/_config.yml b/_config.yml deleted file mode 100644 index c50ff38d..00000000 --- a/_config.yml +++ /dev/null @@ -1 +0,0 @@ -theme: jekyll-theme-merlot \ No newline at end of file From 299b96ab6296556426ec8a56c74e9983764555e3 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:25:18 -0500 Subject: [PATCH 195/577] Delete Patashu.html --- Patashu.html | 83 ---------------------------------------------------- 1 file changed, 83 deletions(-) delete mode 100644 Patashu.html diff --git a/Patashu.html b/Patashu.html deleted file mode 100644 index 9cb27b97..00000000 --- a/Patashu.html +++ /dev/null @@ -1,83 +0,0 @@ - - - Snakefall - - - - - - - - -
    - -
    -
    - Controls (hover for hotkeys): -
    - Arrows/WASD to move - - -
    - - Moves: 0+0 - - - -
    - - - - -
    This project on Github: thejoshwolfe/snakefall version ???
    -
    Check out some community made levels, and share your levels there!
    - -
    This game is a clone of Snakebird by Noumenon Games.
    - - - - From 92567dc63e0d1ae6879bf8f6872a1f223ddf7222 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:04 -0500 Subject: [PATCH 196/577] Delete index.html --- experimental/index.html | 16 ---------------- 1 file changed, 16 deletions(-) delete mode 100644 experimental/index.html diff --git a/experimental/index.html b/experimental/index.html deleted file mode 100644 index 05d498ae..00000000 --- a/experimental/index.html +++ /dev/null @@ -1,16 +0,0 @@ - - - Snakefall Experimental Index - - -

    - List of experimental versions of Snakefall. -

    - - - From 6a34d3da5380589a1047ffcb95f3c82c0e4f3718 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:36 -0500 Subject: [PATCH 197/577] Delete sky2.jpeg --- Snakebird Images/sky2.jpeg | Bin 162621 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/sky2.jpeg diff --git a/Snakebird Images/sky2.jpeg b/Snakebird Images/sky2.jpeg deleted file mode 100644 index f09d743e7d7955d01ec27092f26376c8b27c8874..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 162621 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

    e%^s+y>^S$7rK-=nX)pI=7g!sxap0{%Byg;*zBP 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� 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 z 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 From 1818a4a7f1dc7f4a27c5efd09d1419cb7831c708 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:37 -0500 Subject: [PATCH 198/577] Delete sky.jpg --- Snakebird Images/sky.jpg | Bin 121572 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/sky.jpg diff --git a/Snakebird Images/sky.jpg b/Snakebird Images/sky.jpg deleted file mode 100644 index f32dff14997bef21b897a8b244d419791b6d894c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121572 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�&MH{<`ra;QS{mbZgNa+7&cJ@H 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%0D)drPq?~#uK{J2gxQ_V! zX7Th@Quov-RAXP}1v!+lhz$lY@Hm;{LE+-Gf7T5o;rv=A&?9lD7=NW%(6QVi$*PEb zk5uSa3?Ie8jsnvu6%S^+n_t!^k}oAB-HQ885jqEOC7IahnSOE;2!8GnZ7Fj#o9Q8Y z>nuGF(Bk!V+ z6S~PZ0}ke44i4{j%9>mSCY3}7+vXmxBXw`a!gx0b$!Uwa(z7E@uin?(eN{-&oB8wc zMM@9;yY>G+ne^kiD?|yEH0)cgS5sFF3+>GHp0$R*+LX66g$0$}+1kF5-xp?Jm!*bb zd_MQ%JO8#LOhqUG>p*j4<;rh7ElByH_l}aKP>%HSn*WWgc<6X#pXVypEsa~sj*jT!ISCoT;51iY{rP1|~i z3GQh0z+)}`(XcUwd`m*8s|<^DK`6pgLD3cA<(iLZPwQETh9d$!Iij$);`B+|(dFcS ztXKtY+?l$wS8qL(fSla$*&|I2UX2bz^u7o(_EGK>vM46^pTbi&(wpt?CM4(i|6_F* z5w)E(bmsi~+pB*kzJJzE7i!X30(?zQV5dII527#S&*mh#EAEgq(vPW7U4X@uoVW*%%XBO@QY{T2Y zb6Q|rrlqrKu!HjLmcph%v!T6l)9Hda$yDJ3zqkbIq_BT%N8yu$wFeQ-Gq zD>e~=8?DEYv{RQZAD5CNu56y4<$K~dUxi+9JQEX$-`4vQ8#iY<>3?E(H^P;+chGv{ zZwogq(~D%@8Y$g`IOKR&s$4B^)i&`iExmr>-jDyf@YOl)g@5$7|Mg*7!;Fp&yx9UX z@peHl>z_TL9XiuJDg+%u@v1+r%g)2u1L{2)|ARB$i)htVN_ykd!DzBF_rmMhEY~CE z74_Z19Q7c;?MWTv6aH3`z5Nwiag3_W2@vT1iVJYu z<9;pP;U&wTWpTmQRv5SyJKmyDHR2d}hirkH!nPpbB_KV!9WYidXC>x-C7;1H>C1RvBtI13%xg!Teo#@6)Y|HA0HN;pQUJN+3+||>bssF z3HbH6cCnTBgI`nK=*Y>;eAuG)0~%WU$hZQMdgZvMf;Z*Ctx_-T#BZS>E;>EiYQrNn zyVT2F3JQ$+%@{wwu6<=})kJ+D1ezXS0N*P|AYr^{AM(%4jFfMG@k;*@V?7ZE-Tdz1 zFu?~^D7<5c29l^>u#G4@R%iT}Z%){S^8?sN%Y$}x@fkAE=H#QBy9YW+9L*4TzP|a@ z!01JL5LkQ~Wl;XSV0Dy|;b}CRXv8PrAgAAPG9ZDFl2X6o)=twZSo!L2u!k~VeEa*~ zfBpH|#dC%+xn*9VIdqQv-AnMSP?*yPtkGT4krMCbso0_JxEDTulV>g}lvCm zzt);nzvR9&-j+C~6RFLd5_ng8K#XXRJ#GoqDcVlDw!G;)2an%#e6i%)GTca5wn#oG zbgn@}mPDWAs5WW5uWCYBS`a4hF&nM2o=4f9B-hvvW4$5Qah8d4kL)4WXG?BW&8JXH z!6|H{8R36u#8r3I6XqsYj+;dUUb0(6h|w*%PawnT);*TVddarq ztRL|PU*mGHfp<|kvSo2DIT99EOsUlQ4klaUCzc^B4ceP4Q zytKuGFGcM7J`1oOOB{KjRI73-m2hk&+I!?IF|0O~5UeAYZ#3EjS9Kvxq=(>0JA22; z)o#}Ixub#A;~UmW#7brk1@o4@Qk@r7P@P>6l2+xk zOl)4jc>ev2s6L>)SJLKi_q9pZju6*eE3b*22tF;OAD#ocobu$N|SXpa4WBUJKYYudKeCXraF zf~TCM)Z=X9^25x+VHl@n2&Aa5>efeIK*!X6WXF~=pW&&PibChSq_tU+s(eS2LE7lt zcC&C2eHE>vN1Jf5^L*}2uyr;-p&He)oQo{fx3nn}dxCW)U7?8hbS}ev5vq9WQv&EX zd1ds)0ii`)<+b_l^162Nh(ZN!DbU|&N{1s=a!^3R2W6Lh?C5-si?lhtHlfGwlnWbU zbxvgM*3^`Q5&*MlHhV2+`k@^p25N<|wz1)vUzyxcpj1bu>?Wd0FIze!;2=iS@txfu z=Q~Y#jnmznG^}ULAtNhpU>nl1$fuWZHu&Z-n^@vt^{DbvuKwD{uc^RFxNcH)!)_2( zhPP!x$uUQoSQ0TrEU&l34nxt`f=L^B;~%BPACyQAi0C`buaqRtR^$c}*c}$^td*x( zyt{N!#nI(}m$)DbQRu`>C`p2jD5m=ut@=m$2V?5?5%ACFI>$~wteeL_^Tyz&KOHY( z+jE@aMK*oQKO9#9JBBQkq2Q|Q71~rmhNoOL&YC<=8FDyN5WAIyk(Sy|Tl3BRnpq`+ zD2yURXU!%wO^5X9^Ki1lasHzee9z$qr2gB_=VE?5e0!4Ay0?cLCCYaIo-yyK`9DN% z5D~9OEU(^na?+=g@njV}P1IM_5AzH?PA^;6k52m7LcAA~_6Ex;171=omy9z`lCI7V z-uqgv=GoZPYahGW?9s?xdZe>?ve}rCHaku;stSevrea&bFlU;FmT_~`I;3`fc@n9q zxTM&Cd?O1Hi4W{I)v@*U&pV0JRCLUb)O+yjFO9RM|MN=si*y5M-W!nYKu-Fe*}(I~ zBGRTLYkfa|`fIo!;D0Dx!a46t5ZKJRh1-ExNzu$F6A2X#e$Khk^X@ZAL(j$nKLW>QJ}fM(UikN^7U^}k%}4KiFYQ}Dp|0|T?GjwlO^?AiGW`t{DmAc`u?VfFRoo?HqR z$S4i^>QD7aaw&BQ@|J$M^CN(KKkRj!4UBO!hK7;Gqr|HC16QY>vElMz{NdrGFVpyR zsx^EU{ryg8HAISnIcO-B z9@R3RKMAh%J1c1;nN33L2%a`IR>`tq*pbsN=h$N<*wA`#uja(`q-7H+%R#Oy3dust z97Kr)i8vcY8?(fAvodSgSWjt+oj0qsz6DJip7lp6p7sv)>SY~8^u`^SOI(p+-P#=z z1G~9nkZR|GPFt4$)#l39=7xO^3NDynHM*83!|6bs)$NCh@c<*imty?>!AbcVr2BfB z{xfFU^MxeB6q%|{h7*u^JKR^O^l}^@pIN8~LP2+Urdo3C)M&@aLpcYkr(Fx$w(PS@DVjIZcSEt*jYB=n1H#{a2+NPC z!FwMM9qgYB0etguM}F6Df9^5({|?YA{@XwO*StV|bB@v3o4}5%Lm3Q~>upPA^_LWP zWI-x6)+{T(sbA?a(;eBr&A=AKV(E2>p&y-#H~0F?hn?}XP1UWSNTY&k%*2!>IvVMp zvtL!xr>)xAXv}ux>!7+cqKruHZV*U@`$T_t0+&R8nK8#GrDA$g4EO<)z>JX%m06%cZMLo9$CW^Vp+X}4oI*DtlS67Zn46G6q_lTzx2Sbzd|(T8)4;YQ<3 zWf|^$e6c}AJdg!}AfVrtbgKc}uGIPNVPH^3RtDc@m>cUX13u^2_5e>w+v}hV>@IaO z;9o4`7O;QOByfLvGjoYTaw$7k(!VX~Q1-5}`f0i!Z7`;+dv{pPGq{6;votF$I&Wza z$J}fiE&I;Z}}Q?mft5RsctKrf#yv^s^9Jv6C2;gb1ifs>5@=$+&zWXlm!Jb zUIdUga(0c0;#!R)irB6KdP?)SX5x6=_47WIJWN!%u?^mJC2RN0hlN9_g z&T!vM0sTG1X_pN%@~afM*#X?e0br9aiuD%-PnXHQ)4c>4fp*73%n>i<_xAXvJ zqEY5z8o4R^u|P_x&@~*WvmeT3iDv=ZE%+sw;vcOlO7D5302cbUBft&&K`!}%1!2N$ z@wW^i{-5MAnegur7O;Xln9}hzepcc_v!ZOPZJ<-vXmaLui~%R;#sF&oTK%N86vJ6T zp~hl4ebGk#m1d9ftY*F+0Z`%wq(32U9Y(9m%57U;9MT@bH)9TIJh4;$A<@TQI#l|6 zb>^!y1@)yz7A!StJ+obtsgehfw|Z~YB)-1~WKR4wpd4cXtk9A0m<4UCxpq@{SnZV z*!uZ|crc+csVj=mTHuJ){bHjV0RTxUnBoJl+cE+20d7-SJ5C-`L@j;RkZ$K4bQmlQ ze1UBYBU~}Q(#MeqHKLOc){ORONh{NW?Par_Oi)VO(o=V|9jhS|d;^Vw6lD!NgI0mf zxOYv-{-{Ae(s3C*mRuGH2=8q7`J5}t-}n%2i1thdqHHN~RIOz|qs~N`2vPBe(dAP| z2;s~Pb5N3_9bDD*`JB!+R_w#_wkyBoxP9TuONQqHO)#Dq>CWs;QX2>Qv@j#R-t*Pn zTP%%a>qe&4NR?Zm0}PVYy>-WxU!2J^ah;$d)so?med3-LfV+j2)&!!+T7NMAdO%A1 z25tX(X8y@-K6KtX51LN5T>kh!e$lrZ6e(3zgA)8F+jUIys74%L{F+g%&*y-bEz|0a zF(0l9wwr=a6!0vJJg!cR>6EYYEZ?TtSPlG0=wj3{(<+?OjD&lc3t{a7aLC< zU)8}SEFMIDH|*%An-)yHjzt`=^q*Y~93v_wBR1w_$LWb90w1$V^o9yfvW*-UR=S%W z>`y}XuXIubbAt80=~%NLAra()i{yeO#%@;T=%oD;#D{}lS*@L#8ZS#*O+VHZiTaWm zoOor-t|&ST>4oHT<$yS}f!X@Yidu@fW}^ybhGZk}Ow+yGP!(~4B@dHY^WJ0B1ZKs0 z9nx9m4}>pWG`f#_NqhiFt}aD6Nh1dqNp_)j&)vBNdLmRgi*&d263IGqT-DsHgK5cG z+bGM&^)xly^30|mT`;#1yAGgpjIom0dzO4IHElo8Is3yOWL3w7ovd#XAIHBwqYY#Y zZUbEJM%}RX#oOG2H-9~WfBQdpAqU!rtMBt=j4+188}H>qrH-!&y<)wN%^uOH(OG(- zB|fTA@Wb2c&*wrO8|M)0bo0iT$%}hByCp5LGEcWL<=$3v{!yGF#Nqp7Qj7EVk-AE6 zcf%u~E*|k>&g1NXt25?aCeDK^yc31fd&uOgY=gF(>#owC$MkM~{&BAPczW)5LH#2dtn*1{YI|AUewAG_{9wz}2$R9^nYA#A{`h z!I3-g&y5kUy}jZ?rU7SXu0#nO?yCdet+!m&QwFf$id81b{*X@&kbO7{*7vHc$@jCS zT3TaQRzrBlJ7*^_ir&PI^)u<2JcmgB2JbY3&ByDf`PkVjvUMTC=7dQ@mlY;G-nfqD z`DSYaiC++tjmYY1aJ5#7m}6%_FMdOei2m=$$$tP*{>@=rKx&*Rh;noU->mxUX@AEy zD}iic`~;?NthiYKwWZtD7Qu`08xh}F#*^+MZPZc&(F2?QMJd_(g-ugVxi9^M3nWBo z%#zWlcCD(|CwRMMm4?=Of-i)ZIt8=t@7VQ55bI9N!@FNtFTEx^*H?LuHXMtJs()O! zaFNSiNJQ9>$;y|z+nE#lpgMZs<&L`!`GgOd?`C#0hE)NH2u$;da$JfLqZFW8aUfw? zhx*n#Rs?u+(2+`6iDhDLR zcVx>s+WvpM8Ce-PdY=89hG4$7X)1(qHg4lX9GrIc7wXrbaTC9A!0oW$%1k8f#VYO)D|a zW=eUD4Yl}>TiKt^hX<`euyoXGk8Jn2B2aQ-$%g5+#uFAG?t>e2*CW}466RC-PK>ak ztm$FejJ5dDSGty`+RV{1em~!B&4{pg+Mcxs-@S{GFe}J6q@fdXw5g%Mb5P;L!jSYs zJ?!cabcv+=r&dR`=G&Uew^t%JjP!ZPUDmVLkyAjx1h=GU_M2=;ptN&QYK*|nBN1GY zsv+Nl=AumbkUd9ivi!#osX@WTwGZj5hWGNUH_?WY6YcidQg2^Pen3KT7bh~(v&MD< zrn5XwT2+S4CS%onC+&##uQnHLicBNvlbdT=bt4~3#wW|NBM7=|=bowsoigafuiFZ^ zAhp4VBfd}c_B=!OT2A<5uMI1>ar$cH>*EIIu|Rlr3NjBB7*H*>cSR)p@Ve{dCQ$8< zM;aGRCC|Or5~nm_8!AzJvYTT@B5={EvAK2KILwrP26@+e%)2!JVKe1i>R03Q(?_i6 z2we8_xh7jYKxLnsE{S{0gLlCi=6f$<;p^Pp zL3b(Qv`bVUQ1$`WUohKLfg}a!(5M{iCy_12G^{?)Y`kC&D??wwX-a4md&T)-S?j*y z0H^ouNjG|raneDXHt>$-5Gy_ox0#GcuXM_1$T59TlB3O`I>}$o3KrHf3$r$kbq(f3 zzY;8vOcpyEI*W=T%>VH_%Cj4K@!Y?eKK=(td-tx$*Rwm10#Dn&9~*Tz`wEViUAr|} z!Jue2%puA}SMEQ5HbctCSrayvYBi_Nuk;5*>(4FS{53!(s3h9W97|u0`EcNDVu#57 zMv@4hZZ2%aMO>+k5HM214djRaRGL?0;oG_-?S#g{t- zVqN{!_Pq?x?p4K?KRO%kTomg!GTzah2776+73zkaR&)7%pco54C;w`N)iU>b|0r@e z{(%^((${EFQ4M#m!dVJ?{qs5AF}0-RAm%;gjCypmbEQ$?2>RpMOSnd~idL2C2<49| znh??Y^Eqki7fbL7(}DQNyWZt3JML{z^Sq4_1R_K-AL*8%~H8(duv0(I@5*K>x&7%Y*1dJe}w}=48nztAS_@n zQ)3LeDxq@93Zae*Fwxe9;XpSwgpY%gmxmiE) zA*TaYDX@nweSaJ%1@*iLX!p?h?usNeiBN763^Y=>1ks?n96${D1O`S~)?~h6dZ}M0 zHz~p4Q1H)Q3m6QF28(FL<>zr6mhzb5hAL&l+sP_lD?|R?MT-C*)!b=UHa^8Z_jPvY z5BQvo{nukQym4Fc!Y<4^n|{q~*D*8v84n=jwzb12{z zaP**cUe5$*27CvF`#8xZG3LJ>ScS&5p0(0;ub<=|G~D(vHceyMTrE7tT7-Y_6}0W> z-BT}&JDY8mnr@059PL@Rax>LNDHa?RzB4-EX_HHCQZtx4D~#co35=@V87;y%j$_8; z>fK7VCtV2(AJKa#D|iJ*SrAhdU)=m#$O#{F^uqpAnH>8>IK(DBvt3akEQr^4JK zIm27700l#cX$;JaJKR~SrIuty$sQVi@ixH}tM)Sk^6gLRJg;tCZg=_mOaB|c{JRse z5_j%8-S{BqFI9JsT3E!tL$FXHd^LJXDcG%OKgzm)^vvty)U+WoSWeC&iwP7oQ4%&% zo3%tWgHZ41GZ3^7zxO_BkShB5T-nOr5iCRA7!J?4=>4<kRF9a`GK8-LsDsa$~O z`fcSb32f_W1+IE~jttT!Ibyj76O~o*9fJAwtDQH-(h}6C>~+0U_X^^lkEy8HpE%uZ zSG6>;KqJGoCBWpa<^t?*5s3AtnakC6l|LiO<%C9dZ2=+$(aqO{(6Gpymcrf@drWpJ4+=IxKY&3dA z!~B(M7}?>mgPivU&8QSDABaobFe@89YhzPWhP)X(CEM2m-Vzf*K#jk_P+@E9lqa#H zadkrvf;sz=79xKlx#f(7Z90Fcn+xP60*QM^2vhlI62u_^5aMqG+@o=*p%@ppMEjQiKr2!I;^e5(8tEtvOGHV08!l=Ria6A+1UC%E? z4F;b%FP#A(!6N`tKV}7JwhPu1i$$KKoMwC$K|1v?zrR}4$#UGL$f$PHzT-8#qq>)X z924%sqt8}QYn7S-foc0MkQusqB>&R|%+uCJnx?c6r`u^X~!^Tr5Q7rh7K`vqn^p z6f65550y26U-ioF(urv&@96c)%52g;aY|4`7_qb%eM2!pvW+S1_y) zQq7#UjbO?C6aHRCgivvnsKbw)nU8S7l^d-C@STNvWZGU&340b*V3{zznDeY_AgXQk z?9#heWz7>M)lWg(3=HTC`k~sLg_Z$s)=PpZpn3-_c9UUVuBO-v<0%>>Td|Hh>R z&i@I1D_mRPu1fL&e?g)aAYR#0H4zm3x8_0Et_~o$IW*-P@cS`I0)8A;T2O1K|JUga zOBaGWjXQLbXn_IO`-X1AbY_e*S11oAtJHaionLZHmFFNMRTYXei!2|!QO3gqEa{JJ z^SbbdemQlc6~u|#6Z!KI{gGKpntVOS4pB3@YRR!22kqC?8q<%vo4dPc*V(sxevIDN zv9*zzW3R{Cq zotOYad#`KJHQMD=BDT_&-?q)}MQ-fi3Jqb;g zj1@DuI&aCye)2OTxsw4Dj^r+gCIT7gggeLLZNOvs8k|d4-JH0#s0VB}_ z(Vb0}M3%SDA_T$;wn9ik98uWO?4=T!d)Sy0yj|Sdya4mcd1xAxtQ14*myS8KDhOl zR|1|O-GX)|v`I5dy!FMJw|>(ow}nBkazPt!H$>yjx}vUJp0)B>xiG;Hzp zUyJLuy2zoT@7rfdl+>#(Lt$4RkBPE0vbMtxoj$bhUgsNV*m=Xtgvh6c?3qdga$b{iBX5qUXKE$pO2O${Pce zo3i=_Xw-hdrZO$trJP~4#Q5ZJuit`iqM&X{t84zq7h-qu!+|xEs=;tXpJAi)@RVNP z>DG{e>0K;=|a;cjR2!Wu8HDgdA^Zvkp#xQzs0qTy+<7!2RCj;F# zb$Mu{2kbdW^|fX8b>Z--Nt(S>YqN1{>uhBIL+YF84p~bapH^UeLWyLf7pLsm>^!5b zNdQb>8`RmnJA-_k1W|Sbb~w`cMa^`*3(CMySpE#Mop_e}cY1ABJ}GK>pfp( zmXEcjE6(^r?ou6nIQk(CQo%x*#v!XsRu&Hs?z675AvsYOR~t*MDl5Fru5R?WipA?< z+wyqJmg|cw&oddEMh-M;xaq39rn(AIs~FU4SKp_>Zd=2Uz*OasuT>vOcW++sF*wAl zA4pI?pR3g|MucVpf9H6%Zh1B?XZjgsb<=VtNyH>Lwy^y=IFd)B&Y`{I$|@+&aVEw;}6Qlx-W7p*v)!g5U#^N z3bqDaDS$zq1=w?LHuq{}l`ns%2og(oKxQD=B&Vd5UYd5{^0fees~;*Y@zCB|{m&v$ zo>7sc0*F!I!Qm>@)Wva=zkxoP3Un2fevd1RH_R-Bq&CNaX5KKk?{VDy_Ntt}4<&Vt zfuH2AH3pFthy5!bP>NW+5Ah;)R(GO(mag=Klt|YS>}@6>?7hqVj2Vm_-|v_UvIZ34 zm;45Q3iPv00aq*mz*(R$<+A=jlhq3JH9&K3zL@0ec5gC3_BuHqHb69r_b+Q+Z`Nv& zcC@!9S4`1%y&EsNY{T)*>G=8k<2xVel8Ph9=arhffoW)kS0mm;?1s`_ILBtu6qMCpl^wWu%IXakXjivpR%a)Fh<8b)wZ;N;LT*)LRWzmz97 zKMi;xf$gCI*jBwFJ7VKj`sZ`zu^bGkzu8JNT6Cv#M50c-q{T#ojq6na^{dXGUQmn8B+|^l*u2lzw$R zyxMg&tNWDi=AW^40sdH)&0BWCn@^qxQ8E4(JrwO;6+T|k%Q{3~Ypknu4TMfDCK{vS z%x}_g0yp*dRR?aFe-sf9a>lTK@i5g}vr)ZD#gHoS>i8pb`quP zO*hEXQRI)jZDQY~HJ01>koGc~E+2i|n3C0+-RIp)F}1L<^Yn54(n8W8=w83N81I#f z`}ICHn{qM-po$Vqhrv`KtNHhPWCL`NYp>*t!zSClS~Jf*5dBB+-R_aW!NDkBrC(BS z(SKNQn9Y1ju%NSUubG$cd>0DU@m2C#YtYuefVuSgkc`|uYGvPzgB4lJJpz~DfYPUC zpA)$p^lW~TB2rCbMm9RnrUz5|Ycmd)=rHw2}s4DnM&-LIvBt3tT znjf~X+M9Nm{~}Zz?@^GNqi7KTT%{hC=c&oxOK<>wX>-$3DI-qX?wG1=Oh(_?rp(F1 zI5|A>zDQrZwQDdPi?&$doikoBd^=QfV^1nKDz?`kNzwHbLj?Kh^4=Wf(}FpOM%5jT z%AwA%WIG409q2PSU~e6>Q$Hy7XfBqj$ZsX0sW)r2=G1Qa(II;@8$bJagx2EIJf%AN zov+6_j3qspQ;!8ql*Ti>%pjGui1}NM$x|+VC$Y_K{Vc#K>dv8pDr=lg9{(YsAFQjg6=3k`@3k3D#y)^f*-q^(1d)6x^-ctUmyQb zCSRpV;II$xQvQYt=d64BrmW@YbY(YM_@<9eowc<>H3ejkCy`W?CJFS>65>qW_mHGc z7ldv3Zt|3pL*+ru#)Sa6v8drZ)~t-iDa^yRi9?`t-T^b+DyHgDJlhJx`gq^5M5*#Z z*Qc&J!jSfdmFtwg^=F*8bh||B)%yg+kziB?ZwTI{YU62k(%`cq|4VUjzf6lwgFB8( zID3XwLxI&o-3H4O<%y>?PAH!;&0!q9Cpbqkw$3GIZ+#9_2v#X@NK5t|5R}sc972E! zdy!GzJ(Ca*Fv}q@UovL9G2#Tk*PmI{O09o+d&%0-NmTmsUgag98Pg@3c?#B0E|s8Z z=0k;|8v5$(7T0vr@syyLTCby0#B7NYq&hSzPJ3g}EFmw%YkgpJ&^|pRF*ubo=G+{g z89bVrbAp+M7<}&$mad3%FhB-E_k??Lay(-L%b+RmZVKGw8$J$n0}hFq?=kH%9n=5| zCrQ8wVm|D+GbI~R_Z|nX)5PrzbG{xC*dA6Mly;ER)lD?5BmRzT-CL%Kn&VDP&CqD& zs!ndu^pr!gR=z$|wxg{1s)flyk^i3=i~>926=7%Drs|&k8%-HEMfh6Ciun5d?Rf3C zYgTuy#@^C%VO?q34p{mGAehk=;M1EYmru!tk=eBc1J(Mc7~QIAiGclly$xz)`ocD( z5~;^%U6mNOSuO;+-bNF;1lEonMUEN?xbIMUG^4g9dxyX_allOCgj)SayKG6Dh3t%D zkLjA;Pp-MaNM-$QPJ}tt+x$iF<%@?3cq^=R0y((+El~MSdA1J{4-Mey)$pgP-!D-TmEx@ z9qP>evOZ^Qn&0N!TzQ9dOvs!T88p&a`?X5K(l98EjWcCYn!%Pz`?5p+G0^zTye#n!XD*6KNz z;v!)}j>C(AU3QhCZ{Iu3U7yS#=PyF?ZxQj80WYq|<>YsmlahBTU+o1859|=z73MMw zU0OWNgK@BG3k^eB0x~r!c7|Gtm6~T1zEa|!y-Vm@ujJsmG9G(Sp6+<&np=|!C*PgU z2c1jyyjBm>LTNP@NuGj)oL&nOcFbDoU7(I1-=4*4L3k*PNcBIXUh$>u7<{D@(Co%Y z_n%gsOH0t)t-vZNjn>mq_XMeFLM-Upzl6C^q0b{683zSOxx z9DR(hrV8)v!xR=Mn#8H5o8yyfl#C~5GWoLltHn7@1U?g;91tR8i7z(a4A7kOH*$oD ze?HfqY$X$GUBVk8SGw=u_UpbZt(0aW# zaz>Yxo~daid4*W!9^9bhJH_v|k-CEewTyDsr$YM&RMg8wB+HKS9?x(1jsZvew zHZ4oJuDFppw%tG>fw`{D8z2k2Z4+FKOB(bdjmR*RAYOW~9nTcw{dq;uu*4Q1Uq08wPxmlxh=jmuhe1@;@vl9P{jFkZu zr*9OO$~(=JP45&w*KX9p^y|&Kwd^p)@a_u_qydByD( zZd6&MQzm)VSJ~#ke1IlS(lT7D%>oyCS7%VL4C8MZTp-^l?=s{S>tm^}YIlZART(Ge@Hfm82f7{&l34WeFwCj`~6vp)1s4C9d^zoJjoxNCIvhREEoC;Hw1*Mk<@9B3A68^9D-aD+xY~TB4 ziaP43gMbADW<&dNr+il_r30W{l4GN*TQ52%B7w6)vwGt zxxYRyxlz?r=X;a~78n`Ln)CYNx5;T^yZs+o_67BOv9j}Xr2hANTAOF<&w1+>yEIRQ{Y&E8@QxESxQnE2@e^?}oO zMXx`@VsvIgZMQc|P4ovM1n<5-;CuBZIupG{Thwg)E`+V7`6%ROK`bx&_{t#bXgJegPK|+oPtbK&lXWw7{x3$jEYmh%+U> z5^L50>%vzofvnFLYWM;uE=F3bAwa?bZtR;5t0P*!Oo0VGLZ7rDUkS!Y0r@OTvL<=Vo_&bXz~zu|pXw7+`B7wcfgX*P^gt5IE~)zsY{JrJZKY zy2zbdS6_=6DUmi+d+O!lWYbk)5!YAa8F}F)h3MgcJ25Z|A*-qwXQlSYnYgC6AWq-#$U(I5O5u^DVX9^M8r;kfRSpDN3B2)qpSZ&kSAIpDDR7617H0tj<45n|&;4-^_st}C<2 zbDRBJGH+LYn?>ouDjg2CcS>-x%{K>#=EM0vjysfSb*|CM=SErW6klzruGH=OOOIhqjO~s3O_`_iP$LC4oaIm*7Hr4l z3%L|azO!l}A-vc1r**7EM!12n_&|7vS;}rNJm~7zu5LBQ*_n%VX2Fa30l74eNb zMv|CXFG5q;JFmPgkQ3hc^#H8G>l&h^WO*WO-pko=SCvZLf@gS6aj%8m?44r&>gbyF zco=h0v1;6%&9AkiY~JtZNnDia+IW-9g;5pPc}X7Vi>*;jEg)%@0-k!#kd3X_kgc|j z=v`w5#^E0RVtBW8!QBjrm{3pMEG@X~VzNQgdm_R1?POR?XN^WzM0s}ItWaY8hNMNk zK69LBFp#1)3#o01UGr+J{3xs}?k6&aEN(wn5Z0ku&yQ=VFsou@teGw|H7@FR7*T4M zRj6XU+|8P3;MKeG?U9?)W@4aJK}7+|wXk~VU=7X|iO$VJ1=jTRCzf5$ThA=m%@13_ zKb4^H$bk8;JiA#fYg(mqxaUsW#*qnlOFot+9%21>c+ZlJ@@Z?ge5eJ_a;&pvG{DUk zvl@hu`wdsZ1!F<3pM_#v7}9JF#mYvukZh(yS~u_QmgY7sQWfO}4ky5lPEenf7kM(H z+w`ErFwZV2jM=Ymv;LtPF$gB(?(**&EpiDGWy`k{(R#YIs7M{ z6*qI!xRJhjipEauamJ>i^7=;@!uuX1pI{K$-o91wkS9sjP|sbpAiVm7VSK_*(&n8p z&F9RWulJZu^<3#NEShZ_?@{Q8(SMkQ6Y*~y4@msU(Uj1x+&xS zu^zL<`5BcIqHH(o5A+BCeufLsPKhJi2%vdK?`@M4Ng(L9f%j4`T#$;McEeM_f;y7jr7HMmR2OkI`66# zwi5$l-;HjTv<~?>w^939DvZi%)2avR+4@Qds|dX!2a!U5F+E!0{J~KheIY5zWGIqf5tIVy*@YWaC~P4k;YrAZ~%w&B8axs0^T z#;M|rxh(}9*$w2^X?z|Sfqo1ms{1rdsDeCr6}a82amtL@iY@usr_W=#;%>5&dt=M- zxl?^SdVTC4BC2}r8eWWb(FaUnt|r1C-H=YLWT8r+`c+))57)l0=-FJ7GwzVW*R&N} zV?WNdvb1?4Sq?3XwvAghT=0I0HL4%ceQ%bztB5?m!(Zu)uk99 zWTKZv(;jZvl(yJEE6N+UEFHzwg)4crnysp{Syi|%>CyBTU5jT%{bC}EO9FkDU)l; z;4QqRmN4By)9uI|UoY4vWh$+(?3ldwIMl(2& zgCRRiR`ec9qsb$F@uc@lK%5QL9+ojkg2it6$oIQO9UE~f(`%mYPpzwA*mjQT2p9>Z zl4HZg-&W!ej*G53h9GC4Q$75e+t`oDXzc9ZxSYZ#jwsyfGR}5G&)=*6Ljsh?5<{y+ z`n=MYxj#AcEAjNccK?FS%9&HOqw9LT{yX&yO&0;8UVeiB=@Umz;N%Vjj+zN*NKy%t z4953+y)sz;*(k1YOk3}Ij_5;kUm57eHXSlP3bh33mFRa^3>@d6~{Mp*>HUI?adT%PiBDZp1FyCYgP})Q;k80w)7!fKe-A z;N`SEjc;ufi|rZPOa8 zJ=vI~mJoDZKdW{r(xy;UZ&wwPxr=hDD4)u9G9H^B&88{xl%ulYs8_2z_c9s_@@-ad z)!FtHva7iVxj1FR@!p4b)~icLmk2!*%qU!8#a1(R*n7t>vEAOoY_cK2uN`aLz@KE| zJ~_2~XT|FK`eh4+y=nFs1CL3XSK60z=Mmm*o4CD_ePyVsK(1SYWf)?^`L^QP%S*@Dv}yWpL`q5IE){O)U*0bTyWCypti!HA#s+rp93 zDChl)+Or>pN-2elXApp-@L@As*?m3lAi*uvUy8ksy`ZzTT)TJX_E3%EAi@TYb2|~{ zA}&>)PbWk{8Jj|y4T4E<hrOY?@w~<0q)t!xXIm*+P7A(B zqs6UE=GHcCZMTc7B?n|>6^hoPbC?b6_7Q>7^8&IYogcR5xTknl3<>3u386Q`t{)Nu zmFN%tjw^O8{}?&Y|1~iN(JUG5;^ak!;5Ur+!D`=HnP6zFslITzy}rQnzMLnOCEQh+ ziHg3txrf5ZvzoO+tsf>bhur!FgFdp4sHm8CwN8{4f8vO?0h&EsmV3QAnx3fA23Gui zs+ASxPFwi4!9t)5MWV4^`g5)(jqgQIAR8gQ&J zY4pgcS!t7^J+Bh?4WE}-Q!0tcu)sqYI2E(P^Wxt5?3p?x&ET)iIYgCkI_cQQ*_ zjARFcO}0_13$K_#+2>a5nTlqq_k-^<0%GH~l&jCzU-UQ5HR`FlANmLLfjn>;2T=Ek zf?@2WjmO=M(*dEO^$EbGvyn!;pGrPHHh@v9oP*?ts+h;cr&TAFD>()aUfPZURir~! zD8}qW^Y^#U{wHt3&m4tGBCiLnhU?bM?sXnyW*-$Jz%i;V_k88z#ubMKY#oIKJB~vn*M7Xi$aLm=8P~eemzzW$ux9Zb827QUiNI$~kEg5hN z$k(Jro|vVDo>VA5Wk@i$bG}yQd|Kynib{9fPj1BwJA{uaK>hN3LxDRtpHT z8|6v^5DjwJes3|mTREX}u^VGu3&|lll*V*bqwEE2k>^h~U9b*|A*PnTn%2FpsnqlTMp= z(5DRZJ3QQg%vwO0wsA`90nv{3@Pz3idZKMzGdzDm6_N^;RX=eQ5h#)K2aVrI)$)wz z)}D3<=5BsJz}mM*YE0_4<@Y{{!i-L41?(5z%S0y6epDyPp>EV`CvTNV{hUrt)&L> zUdx0eEJ#x6wQ*S>`D>{6b?c0}tvn7rXS#@axp`Hfl?r zu6G1@KE%)viyC*gQw$2cPFpVw$=Wka-P(T#k^n)}%1#}9ix{&U(YOA1j1+d~t+c8! zDcogrkaKgV(-RHD)Kt%SePC2ae{NSGTY6eZh&NADEim|B(g}}qB zCcT__5lc>EtqG=QIGa=othh>ZFPG$)&VJwI=&qFY$Wd0|tEcfs9IirKzg&!NdV3T! z=%{wO7mCtTm%wX6(d*%iKC_3}p*kDdN56JL zXEzf)$tTbmi#?|<9hq_rm+h7}(ZA0b^Gu>kSL8Q&u=9O$@b{)*`~Ba3++RLl>;t8? z)O{0h9Yi;;^fi6U2ro54*k<>sr6K%Uc(WTtEfpIFbt1)$&Hx_AQ+j4{}}T zg8UW)JwpCaS=oAQ<3#UHI;`vy$Excmj!qyp9oYj5=u6h#&L!f|IkgvmETfaP)FmpC zM+SfvFj=cr03mJ__lcvb7w9K#Nu?fxfIR@ajoPB_oi15KDb#3>bdcWcJ{gIyUJEcp zzwhIpeIDMNj##G{LbvN{*7Cj5StO~uIzbR@`<@!gVL*|{1X&SW2(x^o5gYYN;0Gm- z3g5)HYtzjcMDM>q3wWI>lSK-LMXdD#zPgK~SWgu28j%Qc=H zhZ)Q6ljr&f&=Ue)N_*K&UZv|VOg;`XeRhniQ4(wgLI^bz#R$8t$Y>>7t=F(ahJL7E zP2{$gGIn$t^#|ogEGu8)CZ;P~oVch|wXFTI^23E10U8aHy!9hG@uy5Bv#^2j`xVlubeFuaA;gB_Sv zed2JBj<}oGn#+`oV$iqn`BANX`|Y_GoVRTX*N|b9TN(T+6uxv?WU;tG@QOaa&k&@_ zoVufl@$4-d@I1Mu<@!DP-ALlTjdFxVlVk!^)}%u_m@*ldO`sR@g_u^xF=KmR=R0S@ zXl!CQLBE5=BDX%68Qnq%h$+oicuv-y(N1cDuQp}}xvhNS;71xuGhQ5A%c(Q;<<0;#9tKsJktW^+*<``5!y( zzGvY(&j{l7O&t^OP&d}@6z&$}Sde^9EIISgNY6NHxe~pZ3LCwB;JY!sq76y0K}(Ap zW9~?xKV-RFl%krX7|!3Fb9h4x>{(cQoIOQ9#uaDtv?SYV);xF*35#C2fE^3deK&Hi zl-G(XCEkPM9kV1q;6i5!H}s8>mZ%QXJ$*Y|Q{9f7MN2|}YEMCM3$Cw4am~Yg%9a*t zElfFOegjpY4?Q{|gG?g}s9N@oKG_SoR*}XUI*E*3la!5s+`Yn*#q8574)={MJUvQS z@s_M0xP_8KbMK5cY$)pv5hitjf;2gr=Pk6q)^G6-S84aAvRwI3 zwFaMXbjq&)qxGl%eQx->$>RT@;k+M!H@VZWs!+TD{w8~0G)`<>*m%*Cr>1=O?EV>} zqY_MNKyB%ptpdH%#Gt~$EEBf@C*dm@;Uz6`ZQJBTQgC4--4gA@(DL8nXO{8>*^Mnv zO8Bk1CfwP8juGcWa)g`ed22UCS9j_w`E?q(JZS7s94h9s& zWy!8}RM`oE#6btm`SF^msPh_-pS1d84g7q>QlLMM0%4M;of&o?ck9M>e$qQTf30-S zddZhYJC*yQt5V!u>__!o#B)x;lF{3pRU$Zd(*lNhmd7hZhlz6-@)L)Ea-BC5e6qgP zx*lnQp{#~6WO+e|OD6bm&YXBp!e)&|i(AZ!w{KR+Ty8$n?m|2SM4JypqywoIpdD~U zH}e3mv#O7bw6`#(J`4?`r*^&zW=Dh<*)9=Vvb!QzTVOmp0u4$5JZItO_$10l>eLgT=hi^Dt=?RR`RlT-+ZfbXmtvb&*AGEh%Z&|oU=H2U(f4Bf8 z`L%HF2SuhFG%W5{Hk#!+5@}#|OdAH%TyC*eZ|}=@ zB)pA{Uf7U1kd~PWP4oEq5)CBMcnYPr&As2ZQYtHd-5D6Ho(2LqYQ;wG`VM(c(4C!Y zSy|#TuB*N`(YDcTlHXa={<>pAsdKj@C#!)U7PIiQET&ACAMiVUUUjTUN8a?z$cx^J zWQ8-YFG7iP(kuz9Tvxw900dhp1L0HvwHNDjdv#;TqN9K?2M2mN(1rmiR2Tp+0LnSZ zbF$7rH)jdB0e^Y!-+s{L4YWy;cPoH)74u^Fc++fE1u@jx?D;V>>=GXk8{zoAr(z z%WkL&=OHDWRKe*cs2Q-DMc^Wqb0W1Es|kmi9z`N2LEO6DxxnKOThC^F@4>~F41_e# zivi_GulWsi3A5Q1dqXBrnvfMOZnDxHt3Bh&I_-ScjGP{`0zH7st3z&w>_l5ab}jmA zQT+Xk8Sx7if8dP`+%6&nRfpEC=P8LNLvQD*!K3c4=-CPijUq>D>k6XI>}sz_?KWZw zpZlnLi1S~@Yf~|xbNo+#F#MOFyX^4iuFy!(HX#yVw=44+Lv1`I-?Y+29EIQj31x4p zqd7bA(d1}nG>boM`-VwAJH;+rk5Ss4>qxG`y7`^p7H>%qlfr%{m8_S5TUZawTCY$gf7d%4G4^1 z3K^)%0j9MOWPS{YkUzJ6w&WfLmGa)hpUVe|UZBir$@e&%Wpx3Z2S*2gN1Pkj*POvr z4y@*2bp&92QVu<60AE?0DAmyhB*u8|dn^E80?Q(x@(JeotFy`=KNWWi(rhqa;q}bw_*jr2By(bE-^HC{}a^zFwE?{_CI(n=JV*VEFg^VnYH2Iczfg2=aKS{AcM zUf-js1m%!*Gj=TQn-=xYNtl84bB{d}o!21`gM4)|<^p?XWwN%2zgf4p5|x_Os!gni zvO*7J8G8%SO{DahI}4Ny98B58!+{k^;`Q~LL4}()%T}ko!RHY{I*hM_v=A5FyXNxL z;{J<1FQ}1Uy@#$~oJRXPf6MK-w56BY-_fCdD++VUyrNLJ)(Zyp)mDOO_l1qcPaJ~| z52Ksdr%ZkeLFvU|CgMUNCo?nhXL*)wvrqRTt2{Ef?ek`QWAh@7k)NYo!VaTd^1%tm zRo2zA28=;4MF6q9JrGAQ;ychM8$xLx2fDJ`n_Wz_Y{3VPQU5fFN_JY~E;>99$Av zo~|d|5ZM=dc;bE0)wKyUpJh(xet6!tqm|otkb6zkUo8#Fo)-LL-}nRSw1;`9?(08R z?oF=XVmBn4O7lEVJ!`W@)3ZW>9rdzW)|K1}W9=u};BelGSHyAJudqSeW4 zmgRu14S6cie|dIdB9Sop$Qv&_CnV9ojIM%x8(P-4WMzR9T+mDQbVU!DZ>BvfXeJ1m zQ_q|YlX`fIDQV+@q*ZJSoa#M3I$+e7HQz9|AXFnR%R@8q0GEWmx`YCOl&EL+cl<=p zsGAHG_WF6MP3ZL-6E+|Fl$78H|1cj-4v4kOPaw!?5d2F&Hq=&V|FPv~xN{^HuSgD? zNSP!_HwCMneX1Zq@Jvq+JE=6)&8egLyuCW#+00c5S(M)`e{Oo|^Tj3=R1{sCsl- z52L_?;E{Xf?`+?H7S2)bhWAlTqzgJPPi>tJW zCa8OKzElB;M~an8l9y9{oF*Y49|!BUcU> zWJ%TnQqAL%HlgOJo77`J$-f)1DfzyS$X-HoK`W#Hv1-G|000G9;@ zY3p_XHvjBg76IuAwNJ9EPmO1V7PSWT+b^vU80-PcL|zK(F+hBT^P!Y;@@g)3Pne>usoKFi686i3L?gzS6?zsofW@eed*E6wdx;K zPqj@;URJ1hLQj-G6!dg{c2A4^MbOipqv+!}F_HHme`eQzuIy5UW}lLtipRl-V zbK+id7R(b&$Rz1m`go7x<=8?mVD!-dP>9%PQ+1QLI%Um+ANrb}cPEV77btAI9bG?G;8D3i_e$BvBL?TCrghKMHaHwO z92+PO+_hJF;BI3}t-=XFxPQ%S03_~w*T$sa%Ozf9AME`%vMPv6PY0*8w4xkXKEU)N zd^y2LEz#I)CajTX-R;dD3=(Bn_E0^IhPWnXZqkStTGmXvjE*z44`G zW<-6=4ttp@ERU}~BkK2N&yuOJK20l4ZM4_A4G>#um#0buaT4UpYCBVuve_Vn;4s@e z6Bcf(lrd6bB=1YxwZaAwVzyO7RYETy;Lf%gZqwf#`9|I7ADbxthI6sWccEJU3dJv3 zAMraox@{)D&V>K`xlqx;Ji7&uF?ks*&@OI8ZiecNRl0#=Ryg(dG%Lm~FiXC)TTA8Q0@N(A>=O#Yl z&0*w(iS9N7V6>u}4nb)`KOBO!;(z&^+j2t{x{Hx`OT6sx2sX5IeG2aTemn%H5oP|=b zD~cpY#w<)30_~8EjJI7)~jy+;)#X_Q>AmNQH`5T2GFr^xN1jrA$VTW3Ec<9^k_4&qDrv97xOHXTiSC>bD_KS%?qG1r-xcTZV-G< zE$~Prh~wP}cbC@5lAhxhj=6!=0@t%#Hk{KLM_Y_FP5kaY^4@_Q^gFz-Wt}!f*&2+7 zrDf%kWTM+UNy|*hrAWzey^4VWpZQhH9m@FmS`EGgeLbn_C@ATK2>SwupTg|C=3G#Kq zWF5L&LZj0jQeP@&A{JKuA#rdFc+XrcPYcL?K*8d~-dGSkSDg!L@Zm^422W!J@!T%u zL+A#baMQrN20vtDFw%y)Yc??`Km{JV9y3#is~;B^EeAq%9pLtTjIErP z3`n7>e*0GaEB98Es+n(ZN?FaIBwdtykFJg#TG3FrX(UfIg!cc0%J5{Z7B3S<%sbAc zdBdQZiLIu%@KaOlG;cv0&D(?kj4J-x%XWmq-D*$C?Q&DNNBDDso}OEYVx{l-t?6wn z1?!LIs}0=Q`LnS)XVdm z8)=H1D<~pXWM19`-blmoE*ocf9-xvYAcT18GGdoq0@Fl2Rt28csFw|i4K`AxrVXsH z=hbq2yotEM449X1AxjH|B(=!iql6j^Ejhd?jM#1n-^jkIT8)BBQ`M-brZVr9lRQoi z2~7vE3y}slxT>edE_l#Q31iSZ)WQHo9y*22@Yl-Li2zLY4|}a)10%H-)ysxm$j>J^ z;o<*;bDfFEU<-M}#rVOc*)e*3F<ngE^ znyVUu1-Oa?-QB%u72-Y3>|2eBHe}I}Zv6|9v>TBjT84UQw1o@t#=E!Q?T+1?(w2r_J)XLFO+ln+6y6^(oA!fLrfCQJH@~sb2t;bh0?NG#zLH?jT1yY+bmJ4*w-QZFpJzv?Kkh>r z+Ew!rqOKfb2Y`VeU+CxS9UGs>1HArSQWOPe|4FFTIV)})O${Em`7GbkwjfutBZy&f zX`o9>EHOS@;R zJ5MC|b=aX47*pFh_L3#~CR1Krp|vJrG9H|y<5H`zvu^(1ZD{2FZUpK5F~;sXzh5vN zbsE>i2wJL5YB7-^1g%A;3tD6i_zFQ&ceS}lhW)C)eh6wI^&U;2qQuwi=h9Ea8U$|Y zswT*gGtx8vh`A#wWQVq7E=5E3aRR5j9z&C7&lZiV?8twpZJ(VFK!moJCter;w))ic z#JkAieBJ#y9@~ckrs17+34VD&t8djNH5E2HU|c!b)4K+Ui3fe63L0%7rS_sd6j}Pt zs{i@Kp6uYdopx-Va?<>;fc zv%EyXsJnxwNf|Rk9z4))UY{vviEHIOc7TaosT5A?dKr-_kG6g%>SrdG?v zR!GZY6F1Zph0L_h5Jv+zf6nkKn3c8QdU;3ma%}kxs6sO3_^F?#Ue;ngDMU-|w8?Nz zd`<_=UO`VWpeSI*gQj(bij`_eYTSa&hbkcA_!5A-uxgiYY(+G=Xw|bXJI-#E8kC-! zr7;Us?Ib=dBqYpcoF7RA%$5jhjuPJ&lbW*onZmeBb2dsB#tAdv@{7=9B$M-SIoh3kluQ zM@r9r>?Ff=#v`U2wMz3Y;|H?O*NKV&FNs=$c1$42Onj7aZUaWlFx%2{^WtYKNEA5X zZm%mX+tywhWW=Bz)G=(D$F-+s_uA#ty(qAN9pe`?q3_4?A~I#|9ZEWEx(6CYQRSj2 z%X)*y_4*wSgFvO0uPRK;G4|%xj@c~&ldSZ(GbT{8)tc-Rr zFB!}QZ{CJ>@2S<#wQhByN<(V$3We9bzN>%lcfR334p}-ADEq>9#$wETr;c)N<+RKx zimZ{TMXwlYbsmv@-KK>UiWHk-Npuuwjx}K4TooA2aC{1i_8+}4Gsu(23-sq>km#Ez{9`STAQf+ET&4=YrQnVt^x*9nRX`Wu@e zIYveTtGUX4+8>vC<{o;Ft5}q(FhxGvlBx`fo9){QvYRNfE0VQgVkII!jV}yxSB@bd z$zu)n<;bPgO%*6eNyVt=ly9P;+&7_yoD9@V@hO0#YGJwW${Ric|O>Jofq0^uTol?;`7>PX3SS7DJB zzBP*5nGmyTCK05LPJegs_OWB?jClh(weL>JL4Q_-WPth+|07aagZpDyeW`P|(%X$I z7xt~aqch!O$2*cd^(^>0>KEUc)f62JwrIOaHv5jqNs|^PZOti!@3=EpLH_x#)L(g(+$7 zQy-VIB(Xb=8{_L*@tAlGvwfS^w(4YRfM?y!$)1RftF%j?N{Gu{<8!$qi#RppHT-~C ziw?n*;>~7q{AxrWn;jHyi#~{4ww5*QG-kOF?Uk#8IbB+OFHNyQ!WYe>GpoYBUmb`z zG0v%51~oS=ZoYDpqm2w0W4Wz+TUseu4i#~r+tiJZ8cA(#f}^_ z+c64HFRZkUNMhK`Zcr4amTmY<3#ulHgav87;K6WQ$r##mFv&3nA zM>8*%$JW4m!Q%d=Lck{u^q}^H$<9RvNAr?LaM6kqQgcK5{usgE2yK-|Fd5-*93rPf)5>-nkRhhjHUd#4h! zxCt4a%cu4t_KIOM^rw4KZ^oD*4TE_QvKkr|IU*vZ9+ThM*t0mvxEq7mYU)*`fkM=DXnix3{x!95`9>ff( z>iWc?L~rc~-qm`TRET{OSNguk!83B$XX{egv_bQb?tO>$$O7$(!3F44q@d;pr;p+3 z;5K@zf3rN{2rCNT42@SjuC3R7f1YWg4}Gg9ENc--Ct0$U8VPTKFy(lqz))aAA@ zd|xsiYSQYD4iAG}k)I)o}Ftdev|$0o~@w<90>c{SPi46%dJlns}wK=JacBB3cSJTQ1Eq*Q6r zAc-duhFuC|T+f@3i*LlRV5TcC&9k-fsyDW6^)RO#4>CrTDV+8l*nLC!$66NZ<{_^q z8e?3ejw1sCLUXU|R~LQaSS-;Vm6PxsB4f!09c!>K>^=k;TWSfZyX(|3uzz=>BaOQV zXo4PU)_Yt*q}koYS+j5m-trCi;@tU&ax;ux9Vi6MZ2sJ7%%e?{_E|nZK~Qw1>-Clb z1g2iTXYz!S5`mv4sX6&7vXB5{SY_bsSj3)+C8Je`=HZZcbc*YEV~_w;KGxMOO0D|o zI#ci_$h>&wHim|x=LZrXVBw;fg*#v2ur}-+vSw8=Vw^9HJ;=~F5Zid?STe4xIX@O4 zC@*w2*s;2BW^>Fp1>3oB?ra$WA4~R6wL^n60hTFD(k=_4esJN! zAR{fE9CyG{Z;aCnV(%=P0WnXBgq=x4K4ol#e(%0#oF#J?z3{rNx1;j_*-l(BR_D(_ zHQ6NImtsl_f9KbOt{2nxANqO&%F{wfAQw;6Iu@1CpoTk54GFk)62wz>KuXxyo-C$0 z^eU&eNAT>tG+9#NAlQL!jV_tl^96VM$BVtR=vGe9Fg>cto{1r!Qlk*)nv)OBts>ug2= zCB@W1#%XPx?6n|;3%@s%U>#X_#2}UyS#Og9D&t9)luFf7i7jX^)^Kj=4wAJPU0M5G zW4`CP_0c5+SJaWNjr|)qqszSrU!p@dd|fC$Qf6K2m+#l_jRo#fDWXCx7t@3+-D9J) zH?}n!Z5Fhx2Ff2+@gha{hXAn$x`(=r7azn+U_>P_S2hDu#v4P9LB@%IkFT3^LsDH- zsl+=j#ViQSU~eeT_zIjYRy}F zpwZ3fQwh}zKqvRh?}xMPSO2%0^7*%zu(AhXBabt2mBh}-x=>E}B5$X$IEqJJN&gzt zdto$xijwA?YpXurc}NnKFQU&;Y66kxdqlEr@hl&z(aYHa#nau~=~FE%boFeRqRce= z+;ZKUj@~oMSHYS>o&Jvfm4n7M#;lD6EPqoT9;#{VhA_@6qQs}@iRc*^V+*CG*lyW= z$cwAFSm}c|Jm!n#E6|>{Lt-S$Mf`$Guo}q2I-$oOK1{vyYF7Kt1i$j2MXF=~A+^@$ z0t=(BHG|@%{9wewo0+bp(8t*bAeJHYwqomTx78V#_qwVB$q&M3*h&dBzJxv6oq;i$ zTY;Sw5urio?%vwC?6$4X5&wx>GhPnO16}Z_{r@l{?1a#9kEJw^S zKIio#)Lx14CUt((Z#C1{w6k~jMfkz7(#42tnh-75WQ=;`_|7a-E&IvH32&+)GZC0% z8k6*{tfT(;Y$dx?`FB>b8{FUi+ie*Xl)|Vox9l&A{HY}ptpvF80-`=DS!Lx0_l>I# z)%*ok>x9M$#ih#@!rCN}{b_F5n?z+vVqM4KCw}j7Xns103$R4dG7V~hCSB9f3;hna z6fSUD%rUm>=BBr4QqW|r^r#y7A_5O?WIOqFM`2B4qv`$NjinWjW;L!a1xE+>-lo8s zV}LU@uc0=rOdc2p^(r0~#@Me$2VoH8J+<(y_M9WlvtFf4(Ha0i@dt0NgK~}(28b{x zFc2dLlma{Q=+q;z3hNTGJ{%!3v?h1x#WL*b4Ltn%JhvplH~iPlwa=cdg&JVeD@#I7oR`ytHV$I_Rtvr?8<-2rbf}87nHr_ zxn-{@&=k5XPBR`hNw$hw$|u?Yg}G2hGha%Q;&q8*SIDT=G%~nS6q#D*9n){8BkMZ4OiT zMFTzt^T>$34L8n<1HrQ5mJi)$kBiG34eOa$#hYheoIS3h{k7|)o>q>G#$;Fy%Dd1e z@Sr&3qiRE%l^Dtjrk?8smSAgsAR@C2|GB$*J;=v(q@G2i4MQp!i1sDt zP`Jv%Kzu_nx<0-_ppqUF!;~@M;M#_?^z=3h$_aBROf4n8h2@Z`WM{sKV((q5$ zAMVOeKj`-V=_lLe{VUj2`kAjQfbYVo52}EuzILgl<(tq%C#SFKT4l?An{awM{N;sT zy5~P)P>69j-QoD>`}fr^Z?6@6^NYft?nj@V;-G%@jQ3ZCZw!zA=JDIxQ$O>5_2sGm z;@TwZ{NI8y{w_J=OT*tLiTsc34~`Q@&izODWWM^pkgorATI2tq|HBbL zK;iip6w3dByZy^sKEq@FC-oS|k*{m5e|)BNh5KmJAHNMhxy^U>#5a!De(}B~b}Ht` zS7l$G`mgPcmfya!{e^>WMilqj-OL@TCvFjD!E@Sa|!@@h@l9f9H$>)=<8#g@9?_<~<^S=U!js!alTUE; zU;Bmkme@D?M>srwe0J)~Q~$-i!ExfsKj9@6$p5(0{BZabK$udBM)n`?42)f7Ye@aj$%UK_i&QQD5-AU)5KWFi6alJNzbbP^ z5C7>a#QEiAUpnL;9wEP-AbnX&`gg9Qfijhl$Ctw|9`wVP^U;6c3Hq0>pZybFUH@}_ J Date: Mon, 10 Feb 2020 15:26:37 -0500 Subject: [PATCH 199/577] Delete pinwheel.png --- Snakebird Images/pinwheel.png | Bin 38782 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/pinwheel.png diff --git a/Snakebird Images/pinwheel.png b/Snakebird Images/pinwheel.png deleted file mode 100644 index 217c4c26d5931ebb710dc230619c1c5118637c69..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38782 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 From d6ce59f4cde8a9c6ebb21c80acae51596c17cdcf Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:38 -0500 Subject: [PATCH 200/577] Delete g16093-512.png --- Snakebird Images/g16093-512.png | Bin 25878 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/g16093-512.png diff --git a/Snakebird Images/g16093-512.png b/Snakebird Images/g16093-512.png deleted file mode 100644 index 81f63b7236bda74e8f269678e46b8367c8b76a59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25878 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 Date: Mon, 10 Feb 2020 15:26:39 -0500 Subject: [PATCH 201/577] Delete Strawberry.png --- Snakebird Images/Strawberry.png | Bin 33997 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/Strawberry.png diff --git a/Snakebird Images/Strawberry.png b/Snakebird Images/Strawberry.png deleted file mode 100644 index a5de969772f5be78225f85de5e51b45e0b369e59..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33997 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®~?}nd`p*t^y_o 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 LNupBB`2GI_@>VYG From cbed0aa546ae3f56360b9cbb20666aac67b5cb15 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:40 -0500 Subject: [PATCH 202/577] Delete Pineapple.png --- Snakebird Images/Pineapple.png | Bin 71082 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/Pineapple.png diff --git a/Snakebird Images/Pineapple.png b/Snakebird Images/Pineapple.png deleted file mode 100644 index 5046af1ea6261748398e26579fadce341076f6d9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 71082 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 BD^maf From f2eda910b575d3ad3ecd0554ff12ecd68ba41973 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:41 -0500 Subject: [PATCH 203/577] Delete Peach2.png --- Snakebird Images/Peach2.png | Bin 25501 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/Peach2.png diff --git a/Snakebird Images/Peach2.png b/Snakebird Images/Peach2.png deleted file mode 100644 index d544a7e2569ed1cb37376793fdc2f03f79f90389..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 25501 zcmeEu`yv=t|=XH2ohv#C>owbk<+bsrx zKqP)WeewbXA`Jd04B5B={NF;*_Z0}_y34O8k6#SxV^(bna&$u#X1z>2s+e16r=5Cp zF)5`~Xj^}As)5_KX5m*7{Fh9mCE9Z0#A>kb zVSK*ny+V-_%4IU54kZGX;W3M2Nv>@MB^bX`<+!OT4-K7ix`i8N)qsVfja3bch0nzz zdBd{AaKc8U&-2c zT_l*13CV8p2+NWjG}caKT*NfuuTORbN*p}mx%)RQvG+%|L&ER>!5%6}cI}_J=IBOY zWo*Dh-cK=tth=Ftg|_^%Sh4g@tWNPbUFwfZNR$0o8bvt=Sx$ic!3_#iH5d{l4B`I4 z#Qejwv6vI<<$hjT?Yw^ckDA}PYsUWd(|`DC#{T(}((el*qj^Jr+_2X(B6AS^A4;0y z80rcwAo=C(KY2$8OdLcahKz>(5}6j7Pf+?PYg7EH)HaXb)q+yO#(g`xnt#NTkE`mz z4f5e~Z8GXTzn>LT9u)5RyO>Xy37xYp{9}L0obU_EqHvAd;*%QheGr+g{~_jQG&mG2 zbnce!BCF%T`YOoAEq{FywuFE}K764gUtJOv-%Jtz^U{nFUqPwm%kX!JM;z#Py8q_~ zx)=mx{h6?Ws+`Y-7F+%!MJhwYGk-{DJH+Hq(PP}aIha=vQ^D_SQ$vRs2mZXr6w&|5 zc}*^3|C96o^!a~&<9~kR{}=ykNB}N}^t)paA!Dh~eEjt$TPflc1sl$5gG(7cc_n&N7YXD9gggrpXtr6IHY+s8%X zk~1-YgY?vQc)qqHREtHPqWa_0d5d%0)$eqYjjlypXfac9SX2t}>pvrJS`4SNKnngi zN5HZt0Xd@HR+tqRTlRO2k8`9lV5KJH3bKu|PLc5X-=cH+T=mD9HezWKkfvCzgBrEX z?_hT~y1}E%=I0|sar^!?aD$7MXYt_{8wDs^F0M+4o4!gtWFf$EpDpw6jbimAbgSp8 zR¬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 ZEo}J0-FAHdUc15f%h^jNZ%#Xe{13mRnuh=Y From 34a77dfebcafd1a0a308358a73e18a77cd638a7a Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:42 -0500 Subject: [PATCH 204/577] Delete Grapes.png --- Snakebird Images/Grapes.png | Bin 48826 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/Grapes.png diff --git a/Snakebird Images/Grapes.png b/Snakebird Images/Grapes.png deleted file mode 100644 index cf43a36c9176f51943f19262e5eb601b0e750f4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 48826 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

    a?c2j5rMj`ftK0e2cu46JK>7v!cF>+mPS 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 literal 0 HcmV?d00001 diff --git a/Snakebird Images/Strawberry.png b/Snakebird Images/Strawberry.png new file mode 100644 index 0000000000000000000000000000000000000000..a5de969772f5be78225f85de5e51b45e0b369e59 GIT binary patch literal 33997 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®~?}nd`p*t^y_o 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 LNupBB`2GI_@>VYG literal 0 HcmV?d00001 diff --git a/Snakebird Images/g16093-512.png b/Snakebird Images/g16093-512.png new file mode 100644 index 0000000000000000000000000000000000000000..81f63b7236bda74e8f269678e46b8367c8b76a59 GIT binary patch literal 25878 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 literal 0 HcmV?d00001 diff --git a/Snakebird Images/sky.jpg b/Snakebird Images/sky.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f32dff14997bef21b897a8b244d419791b6d894c GIT binary patch literal 121572 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�&MH{<`ra;QS{mbZgNa+7&cJ@H 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%0D)drPq?~#uK{J2gxQ_V! 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

  • VVfqvd0Bp{jLxY*o?H2jIriGe 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 R74R;Uyo`!;gOo|={{dQJC9ePg From db9e39761e57a3d3274ea76674acab938fe18658 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:43 -0500 Subject: [PATCH 205/577] Delete Cherry2.png --- Snakebird Images/Cherry2.png | Bin 155539 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/Cherry2.png diff --git a/Snakebird Images/Cherry2.png b/Snakebird Images/Cherry2.png deleted file mode 100644 index 9ee0a9a7240051dd04cc1a2ba4d213f0f1cb944e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 155539 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 z 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 From 0adc456c2acdad4e03ffb347950b30ab66fe6546 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:44 -0500 Subject: [PATCH 206/577] Delete Cherry.png --- Snakebird Images/Cherry.png | Bin 39242 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/Cherry.png diff --git a/Snakebird Images/Cherry.png b/Snakebird Images/Cherry.png deleted file mode 100644 index 95e6f3e4a9260f6d84e65179e6838034e7130b7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39242 zcmb4rbySpF_y3RzNJ>ZuC`gwm9Ro^;NC`MdOG-;OLx>UrDk&{UC=JpB1IU21bV&`} z3^~BWZ@l-)^?l#(KfkqD1B-Q@^X#+tXXn{_BDFPD$w`?=0RRBG+5@G>002JjPkg{- zV%)DopOG^F-~+XqlA@l^)OH4mkFNe1*46MiZ$?8!a^?NxuNu=|)rPs8x`za<3xcP6 zvxB!B6cxiOIb`^97D-DT;m!PfIRZQ9Z>ps3KqqZc1BG|^+R)J5zNU32H+T1VF1w*1 z-^>F&5%gWDlf!_ygG}%BA9&!sOTT}(e*igDB>Qs_956{r*}WEmUmwwerrAK*e)r%@ ztUmK0xQ_}L*~msj!Jy7R)|PZv-GGQ29C^g-ADd6+;r6k;CagCC;= zd+>bWHQw)CZ+<6Rd3`{+ReUW{5GC^0wzv;dLSIqcT{5W#kw_H=*gO==^PTO=KX08^ z&h*Zty^G{%0;Yq_D=j?i{@ku7p5QW?84$&mnRBfRw`14EmP)>>yp_aX$pPyywJ3=f z&4<;u*i=^1DKEBt$$g2+>+vfKyj9;8iU1nSD_j3!6@l=IPvxr~Vg*&faWKT{#&==`8ZPF47- zj%9CW`@L6kat{A1t!IGt`>2ao`<_*v&=LbK7EO_rgQ>>?4Z5B{;8$x-Ipa zLx|4b2WD+&izol*)l}f$5~PIx%d1@EW^IdsZPX>~Q9T)%VjRr%62owgj zB#AEex-E!tgR(ghDEPU)_c+t~m%+VJ;Lwrn+FYA;@H#AVXdU=;(CFI5V-+ysZ-eNuHOm}0pz;$k1W|S z7bgotTK-1TA6!@bEn-T@b6W7sB=};z!&TY(L+H*;#Xp$ii-;Sy2JoDb6#R?Ie3;qJ zNv;#%fw1O#O)T%l^U+TcT5lWBULyi%VI26S(cJugWEUg|*Z4#Zy=(1w!;~U_b$#;=CmjB2kMu88?^sG{RLkB<+^MH@E;6? zFvP&iWX>rsIN=n^os1bb;pF*)Il>r3!xexsaDnz>FW6UP4?5^?8-zpoADY3BA$eRo z7n_=g&12wxSb()sc6s*iWAws0OwI%?S$RL6J_B%G90X@&)ZS;}und99geryO{rF?U z&Ui7LWTfruF^jjz6miDmUnslFPWlTo14s0>u?VXTxljIoI{4^;ooj$d zOeiJ+XQFoa6#o^Cc%~zO({7{wP{TEfMezcQFd<=O(3Pw=;aA>{Ddj)W@ zsG7mFyzPRekeb$Sf1;k?!q#7$4Cfer`-?xg&i-4)E}7nqg6?bqFVfy`pr@KqykM$BX zXSYS-Tm*z!+%x3-QK8QWHu5JLEikwjL7vn7<2$BAmO55yb$dRm{%zP9=|g{`CcTbCkKe&@{eZ*zOlF- z#A>4U_I3+`sJWC>QWEjr=sMXbK1qe?FDz32Z(zkhF6*{Tnd0U!NiWS<Rj5 zG1M*o*27#oOy^TbEwMMCek?g=Qc>_pW{eEyDGS>E4L856La-R*~I zQS?!a*R#7Zw^=~tf{+eEGg~AHJ8Evph^02pWc~X$zh9ve?WBJfPA&h#Vwx81ec_6! zd%M3ce9Kh^cC#}iV9_f6RJF8}&zVnq?p%g(=GEAZVBC`lqyRV5*1v2YCrFZ3H%DyL3dpxy(E7 zWD<5&2K>seU#V`8@6DvaBMUP)AB%^swsIJLi2@IFWt^5risG*m-1@`xGuWA;rB#oX zGL~K3Ls(~=F%P1#^bMgCT#>TT=Ymu3&N40G6lo&%G0N9Q4Fn!#*M(e;fbLfh=n971 zEe7tjIDjsqCewBw%hHnXoP)pzqq|D3F-dCy@`LW-3SI;5&X`YBQJ!*)lDXsbWc{0c zON`}F`uN}YFdEA-P)-hW(J?lhoLqv$Rf){mrUwXz@pa@7y`x?z=CbOMW!fa!l9x^Af*Aj*dW5|<@iYVi1J(HWu z>nXszhz8nHmm6j6G;u6Eq2zUG8+-iGPdQ}XSpUHX!kWEi==O50lKXh;ZHj54aSZ3t zkUr=b`BuryU{fy0;7-#fEvgxpR=2Z3c;K$A(vf|v^vups8Jp-1wZOEZoJ`5O^8P1j z4i8|SDhE^to4lz(_dko+H#v-`nW;LtEziVF+g#;(tQFj~1kb8$lwD~zladT9-%kzr zxI-MR4eeuXKBtbW_|4uY8dQv5~7B=k4QgkG*Y*$ep+Z`!Z|W{{rve^ zt*b;*g!i^1r&1BJ2covrWlmte1P^$2m}>EkG5_R*mFT8dbpDa|%t)q;X9QGo%-C~5 z=i~i@q%I_yi1JsUN4=skyI9Dfb2@G{xXe}x31~D>ba@zT=W!(C)aD}!m=JkkYD;fl znkRFz`CZb$n!2O7s$pl=TlF=P-*@qIrMZ5XT48;^5-WvK-RvAU&arJ@C*O2A)$$+s z!H*Fln7{c9X5BTuaKa$F=W%BM7X>khnxaF_>eRiGoj7%*I_uHTsKN9>q&KfDtEJ3r z3Y1%pF+}6}=r4JBmkQ8eOBoZ{790qV4J1KyB#G(=F9#22xppa{UH6OBT^Ps8s>j$m zIeJs1k=&e^xlKB-?_J}mWy-%!hiwxcMGyX+B4mzbsqb8y4Lciw_U4GX+CKfxzh7~? z)s;~9=6pVb5xK7Y?3$;|$Bij`*Ed{otx651DKtc%!xqJj!n>_c@AZ+!W6$tfo1k+h zUh%nFgky8Q-{=`AKBwEJO1nM7^xZY}7V1UY!1U$96<}GNIcgc;2a6JcSh4o4n(2Xw6sV1cun zqOd{S?C=Tl@bTAq^t;<9uIP-h=zDdh{mia0pLZi}bs#vH_r>+ZmzosJpe*$~W^YxO z+hm`0y&1`F2QQD1y(Bt{Y-{6XFnc|R^Xdn@|6LI%;KMXtC+ECoTX>!>BL5N&41rvZ z_fiH0v-%Tv=(w{rzvf2JY!s&N5_W4oFFBEj)WqudXn5RuEBu7+N|SBQRy&;$Un60a zDHF2{>Uq0`CFVQvBK#fsY20uCI&rmlQab_|$5=&7d<#>wjsXuY^|wJHO`?U8ykT%% zGYu`ffr($S#*x7v^!}zm`VtM8)t&p~bNjBa&%7^!CT~F;fO<-rfeUJJ;gsxYT*{nQ z+dNJ7{@Vy(^4cDnen3V|&3Kw$SB#kREMNhhG?47|Cy7AhsQ4f<+|_Q+kqanRYia_9+V+4g=%ZoG38s@5#u?7Yryn}+6gN?>?qkwgy^E!L>Uk0m; z@&AbQxv}+2UaBCPSGqT@f~Aid!$n`g%y`>a1itV1P|zPXBvT%oFZvJ)UDK=oq>%D8 zSKw1tt#jToGh(S!Yj0pkQu$R|%(rBEJsBJ3_tj%_sYOB73_AG7P+s zkO1v#yjy(*3dK1*SbWn7&dX=t!nnTo{GsM*hN}{4p}yHY<0Q@McE(m1Z41(XPd-Cq zBA{+B#sK5{$z?=bzWE#B2=qJcXrW`BBEcZvc>uSs&b3mSmtD^1&R8St*B;rM7n31DW=g+2aWD*Cr6h8w3x3{%yUW~+~UwqK~cH@H0~@Fi0@wLLXFlb?Ct zVe;C7KnRJ4ppNj7;*SGg?#JZB&Oh|jHB#(BMnO^*b{N7=8r|`vQm9T$J|`(_fQmTJ z7v?u@Ia#Ix0!^Gx4ZQ3aJ}$f$GHn|GLs3z)p@FXy3)A%hwYcJt-N9oI*dFhdU>}?> zV})Z~bXb&X!F%4ABZ)-VBZg+}gNZz${0%kUFgO~*q*a{r{AwCwg}J+odF-vdWxv&6 zXsQD#ER#6*3Bz#Y3}2G)3bs=p-)O`?IP<7bgA6Z6>mp0NDL*4vKm$|gejx*Z; z!N{-zk8^BE9v;|K2A4y!CT4DnRE2JcOBs&$V1?>M#1?38M}g>Z;L-4v_WUbI5E>(Wxui?aiYTy znuUS=l~TkXkzYJcc+#9+V1b?K#yTk9i8Aqk$X_;>j9S=Wq0_2X2Qha?pnAPOD;h<( zddyZ^^~h`+WwLC+Z?@Ck>FgYvxvDD?hdA`6uR6={IvQz6p~8w*X#ZI2ut@GPN~jErexlK;5tVoOFSWUf`UNF(%n3s;^Jz#!^kAXVDt# zIdPRFlF(SSz{t7oTd4~@5W`oqwcNPFoNB!AGvzh5AJ3V^pcBsI1Rv<=m2{SRbgx&) zZ&b#w`6OS)53}{tD40A;O(K~HjhT?NSPUVc;NEn6*SnmgECGFtq=N(P8@HbqwnObd zer5<<(ejAI8i#>kEtO9v-{ZY)Edz%CV%x6>^d9SYAonw$VUr#4h$)O^T}~FK6^o;I ztY)621buYr&Y(lFh2Cj<$#J#=!d?4%bkPL8cVy9?M&JHD1ck9cu)F#aEK6%W;H-4< z2V6K6fxgcUrl&8cLB;4!<#en7GJqow;y8L*HE=fqK2Y{KB{`7gmlER&N5V=F#@aM#&F1Q@Nv_%#zVqDRGwkA; zUO%^c^PHFWXR`RT%-!OrhpO)+KKgwqQlyOLpG!R7ddq;1SiLIVxH@@%VRNVX%SVMP z{mfPQ1_BJSPj$9`(0w$csyyl3RgJy6=Q~x91@uc(|Ec`$p8zCItMFmP@uuDn`Rlv&1>aJtv6&?McRYa7?u?&PIWu`+&# zTdyP1An@&#EH&1^%UrH2#Bv;~G4J=zuVVX-+18}AF6SY2Pv^9b(oyR#!JB)p0*X?R z2Rs??)`Pb9U>$LPf$kSsEolJ`ry9;5bK~JDf>ZDT-vt3wsp2VGrYDC_I!igp1imvY zMIs*kY5aO)mW-$T^7x=!b9(2Tjp z?xx{$sXA3iL^e|(%BC&O=O#+Tbw9!8q+{B_Nzd*atVwr%=E9)lZVli0IrlB^l~f|t zKk_RhlBJ1Z?0)Xq7mpPmzm|)veSQ^OR@0Oq%I)24`EhB!wM)K%Vrjz(KRrOw9p8W+}&?FMh(-w)t|(?xR$l1kV?d)7wq=sxd6; z(S94!r;Y94yk2IhagRJ4Z?ea;aP>4=>^ljXUxY9~{=ROi)tJrm-?E{3ziU;&*m$d4 z20Z!z%cIff?z!piOUSpb1oU&NxOTtgXh(`agzV6#{;13ob~QpH(ChUIy24dQc{WUY z57`iQfLTA>F+!pvfQ;^{_>qT{8A#g~nb_(+p978P(e^AK(m2IeR)A|RZ9xE5pH>p6 z-ihj8rA@DC_~@L~uF44p{L6p-hyx0AbM<06Ccqg;1Jt4?BOofMjW=aWoD*|tV{vT>Qz;<6Si8=Ey`6(h zhM7v4YL0R|E32<5{}5g8rq-O&+^PJUYtEQ{MJS~794zEads*udcxm&4lZFuHUBZEx z1|zXzB$oahs^U~8^3oLLxpbG8i;QUvep3O7mX`U<*V`iqJOsO2Ew z6mjq&oD)|e5AAZ6f$-KQIlY6uDrzBe+b@Gkd37V)ez4i%z3@xFRxcbGB$k1aQjWu> zne4yw0|#WZ%pmjEil0k9YvepjOC$5Aqtp7*(9FYwDCiC<8<${`4tGP7o4uX+R*SUV zqyf7MbVH3|ZU^W%$K#3IIVgr>(IOT)niRi?8NT&@-I#d2IpBdqXJ_tt+4=^<+0fkJ z+XTT%b9YSQ)c0a@9z%XkJ)s4CdGHRSV@hON%WZ$E0yYQ}DOCoY%F{Lo8K zl|qh~b#40-&|%4I+;eM_N+^!biVUslo-YldC=CTLhbQmU_jf>xSBxgC013U{QQtWv z55~VS3(S|~IDJuc5OxYRA%X)t|i33}Qv zT6%|J%&GhlOLgne{7>`Ad)PpUn9en*SwUIWm=g~sv>EfE185hZyx1r$q}bH4-{h`= z0QHL{L5IhIViLm@~*RLT!pqVMXmV?Cd1R%=#d$B)C+~)}tQ1YGYR5EjN4uEU*Xk zg02CEUzH}C8fn0>CQ?TRRLtrnHH3U)AL+q@vy7|uo74R&J$<=jA39^E>^GutQnDln3lj#vuDY*BnQf7jjHTG!rxkvjj3Yfz+vg}@!mUu$0gu0~zR*ul+|fwpjhnLksqt_3Poz9W!$FF0C~-bI?t7W;`vksQ)D>U;wrfj{T6Dwn8S^gQjE^SXh#KChGKxyBjbl>u@ z&0T-O?UI6QIZ@M4xl@qtSZHQ2Fp5J`#>;ZjDfV^^Sz8^ZKUd~#T93#ts7l5!_IQr5 z*N3n+G1q`*S6^)fw}HBXOMn|{b}A74+$*J{eEwSflN)+zjePH z8#0dnZ-au%eK_=Uaja6$^4T0KQ!OyL|GN6S15bXz(0I)nvGKHaS%0qr8MUvf!#153 zeH!*$b|f_gbwi(h1u{IA8v|og%E&&IxBxoTOmaW)VLpVeXsocy^Sx?UeuqoQ$LCff z0#DZE6cA;DPnQauEho!1N(HN4`l2%=+&;S&VF7Za$h3G*@AAz_5S`*Apj@+$>LJ)7 zrKfo4)K{wlxjGhiIfe|AD}X@%_!g0;EbAQesgG!~mW*wlleH;itxQ4BW$C z`lrDHE8bR=w!Eh7yKGke!nK>t8%g#M<=yyrV&h3F3@+8rY%I6aIoOq;H56dDDt*qf z(C@wPNL9zYF3@*%cM9frW<^`qh~RCn&b+xG1%!V2*b+F!kh|={OQ!D8yoFiq28Zlz zc-J><@fIQMVm9W>DUUQtRh#eoT}Fv6r7IwKId{M;z|{cYCp@>J+%PC ze0?TttmUSMjvoC4ezu|S?WTvB-30`t2G%>p*1uJra{~M*tSfCXGEhUFN(VQoZP7)H z#RKcl?GoyUecz-znB>N$>V4kpe{2%=EmwjzdBYC=5={#!N4Hw3enytL>+$z=ow;o3 zjtNX<`v0sV1L}EW0yb8}8!gmKm9GamcYNzmXc0piQN^<}vCD^ICCgu+yg;|)!OFe? zQ9!4u(Eu2gQcD*7c>Pm>MgJTdWo5rlII-lN0(I!H$|@V(1+>`S#g7I935H19vMklj zPap7JD31|NzlW&gArH#mD#F#xi#R#H+UP$UX+SG;DBQsG5&ILbVg12o2;P1AM+>v8 z6WCu#S2EngQ25jE*(EoyzX@Eceop`?fZ6dsr@DmFn7CKEy{znvSk0Hsd3`gKj-cMq zTrA^qA|qk^Qej|o59NHUspk*k{!*;@4yw9it>ieabGJP8W6Ncwg5!(eeW4-wqc$79lA`?zummxH_+(>}D$37;OuxeH{Me`WJ zRy}&$SkcJ$O4SdoFTP~>AQ+0E#Zn7khSS=i9#6)EH#TM3!#B`_1IUa5WHfP0ucHns z?@1el^fq>|2av7PUy>x&-mv1AjAvM%P)W$7-|pAM@0Fco`IINP+{XH&w#KXbVnlUM z;u#cKE#^0)?nQw<9%?ppxVZ)NZv41*wZEEkXA=U0PMY604@*^TaeEtOb<`O|%GwUS zzTeR+ys2t|)S~}J5^y$-D-|Wwh@x`T)O+E)tdzn1dALMD@WPoSG&k@O}n zhUKSZ6rAx(DgVffn6Ly*? z=}ofXE4rQ9%|Pd^MP7{T)}6E=K;Q7tYr4K3v`Qa9#NUdbFk{4lH=_FemrHI@yaiX> z92Lk(WD6YlEcKCCcf5j!x8Ig$f56jjO22|HYE@KvTSt+P!cQ#n=_QWj24ZY2Qm(zk zNq{ycD!7vR`{lx!wfiW#+$UF9K1pWS$R5;I7YP`pgCrkUWQATrxTr#Kx0^r)X0&$C z>}^9hbeJ_$7CW|^hjJpN!l=|GM8TfNJnlQY6u`|CT9SMAG$vt8bYdr*#k?5zZBN*p^nN&5`Cms{gq$TV z-{O1)d^EXD)v-N7gWaP&UC5WVpa7Bqos?K63YJ_)fG#VG)kC|6>=>5kl0nHu_-xTZ zRgW9CN==Md3=wlnZs(1;$3`u=Cn#z$TRw-rqg8_xZ#qjDROdFk zPP5ooXRs#2(oKbc_wcLGYf6P}MIU4O>nnLa!3Q!an!DMP>$O~$A2;kIK&UcN4v8kG zp$ks=sp#o#Zk64yt2M`GSG5kvPs={%&+}@|D%0v|Cm~7g_I60 z<4R@Z#K_`xZ{bC;y?W>_NE`1~fmD6vN*xN4-8rh23` ztUsoPtRkz%|Bued-1ttDxd)s;nwdSOQml3)mb1ZVHAgOIZ&*ca-DaB}67SW}un;+l z4yDDCWY(Xi9p)|7w?n^xM|oC`JxEP7lO_Sx_MUPHLt5gV{%=2BC)b z9(s-aU$jsX-|fQOJX^VD3&~f^q{bO+EP+n7|J6I?<*{FQ{*zND#pRg#XkZX?g9iGMU_W0flkb#>HUq3)Z*bd60U2}1+ zH*jw-J9_B8Mu0)>O{m|tuR=#xOm{zdT5BYudX6h6*c7wBlgWLuJn)6*P*=RCT;lz1 zoIN>YOPKznkIKqjC|uZ+gtmvE#~b@t${gwxx_%^p+Ho80c{DhAOZ%zF_bj9Yvm@c% zKD^P+iOsr^AnM~`@xK3V$KB#tdbcd^t95$GxO)tg2+f9NJtT-*Xp{2r79Q)HyY6Gp zDly|)%D1nRQUIx6d#zAhzwLaq0gs4;y5C=~Z_ucji<>lu_SHKW7#0@;X-+?Ke!)KG zKfKQyq(P0nQ)L=={RsKMUx*_$T3K^CRJyw4jn4u-0u{In{7<-PM> zs^>%q7rtv&bh((LXy_2L_D`!vcMY>j8j8O%9IuLZ{co$#U{|A+7K{)ypLMbhPEXm~ zz5Ea*m6bJv_DqQSwB9g2U$GkOfdA;p*TdyQg;Fi;S{Up5=YCm<$Tl8a!slqK;v#Tv zen{MTlv`lv-#PVH3Fm=84UXr#8~J)N)4j!%F&$fV51_ye**dL0z>8i7(g$BnKLqKw zZf&{ywP(Gy)2uOgqbiGbh^&h;7%%3r|8k{H04T!2{uuA&PkA5RVB+AE8`?LISzmx2 z7@GuGw2zL-Ph?Hg{%?c1%tK$j?VXt}z5=ig%KK8#zIXk3v{G%;Tn!}1r_=xsw1TJH z?69)_S_vhQ@JbcM3(DF#z^aA&nX**%dwsBcvmI(+B779{N|Vz{b(C2@uy7`2i`UK{3FrK@oE#&cB3049tf*<0#th^K1A9=O=CjT_l5gMBYNujkU z?xA1}Xj(iuO|3+EAY_m>Pd3TN_+6Qo``W=;S|eKhez&`GO%`Ky4AY*Y@U&J;LS3JI zfp{gRpSgk)D+J#0{Bnd%3~WHa$Ic*$>Tj6!QC@9n_;lcK>UqtpUm?b93M^#DtA#6F#0u~8Gu7v43%*mo zM5^9)>CW5_%Phd&PT%oXH@D~$3KCl3SUH$`Ja!Yoz`XN=Sa;?*i4k>%%^U+hYuHcKcU1rToSFtxo^hz6+<4YajP>~0n>TlExyRI(oci(-o7YdBv(%J#5oqrZ z7iT5+5BO`uA*1s`R#!>C@zf1I@+42+3=`hhoi-R55qMzFNh=61o4)+x3$uc!w2G6* zIH^zmN`5Ng*1+w7fBV!2`x>{nRM}`2?_Bjt6uXM;%EaGMMV)>fI61spn@nsH>rF#0 zB;0#)X0g*`OBj@*iBUu-c{ihXN7&btH@?>T{LJj$*?!ja)+q1_uBU0&186z?*^i0t z>_g(6kJUhz<;RPOxa>2JD@uj5ny>~Va1b1*h!Ok+>9Ap@b>y7BJ;KH2vLmTBDzO6ZaT7q4cqh6tM}MBEe>k}b*IUny(dlorinGkHodv3nUZTnF z^hO)kf^pTCZiME>xqDM z1ke<@K*BHy>p_e^9Sd$V$qO^`Yl;z=6Bck+BDMOg2sJPmF9K6asp|;$@>^hY zMbCez^tf#eYzP0<_RrB{S<6DQKgY%Q1>;H%K!5hVWf7b?#}1@3MQe&m*Zi;p=QiOC z_72)UdJXTnAi{g-Wcd8d?~v=f(NbcE6*2Eqh_w?~Q4nyDMYlf#t`RytQDpXAWZktxnynC=1_5>kCUn z_6684w}ux!sc+9rJ1x%%3a{yZYizj{QUZ;)TahhrSyJoRU&9>dT`T08_L5rw_YPrsB_JIbxTL&?U`pBz`0INanL3%Ch(7ELT zWkhENN!QgDPmDvMBDDm!MO^EHV^#rvDqSiEkfEVhOpA&_Fud%LP|_sb#eSS&`5E{X zZob9ngKAEIo(Fa~1M4$j3}(Y!vUVfgve~?Mhxt(fVlCe1rk+SS*xa2H`A6^pu_IoC z-DIo7pE7=`k?}iR;Fm}6cyCsck*1)=bCZnIxP{#42Ib*Zu|5$`y{ovo7|1$m9B?>` z?JcX8SaLbA1?7rUvauBZ&nYRpPPe zAl4aQtrG@>nKZ}2^!{g}r-Mk}^(IW0E=rleykXiM0SwBpd}fLboeY}7*CkdM{OOq0 zgwF?}+mJae<9$p^U>~GvrfzcSwBKyUVy$RUyBrVPe^fgE&7O3E&XV*=ijrk}y?jel zh(lQ6H69Q-?c99?8X5R&)WRrIVtK66;ZS9DJU(K4Fe7L7GB}pw1;geb$C#f9M%u@t z0qb@6WLmgmt9<)<)r@$o`)-A4=;Gk|*SAV*GJO%)bw=Bs{MB)#&DHDmoV%V{h*iZ= zl9{YlL=}c%&q0vP4V!HZnD|c6;t2?#BNu(=s=ZiHPI*ExFXJzU@CFT9Y6V*~6NuvD zLk`OF5@wiUdD$(4p?><@hpo6e-tx6j&&L(nn^6S|C*-)!cxNJ3k|R~Wb}%X?udQ$t zb8rUZ3-pN5u9b2dJk@)6A}~6DglHqzp^oUcmit@!cqlrXU=uG&#SzksdyX z@>Lb;1-IZbqKWWH4Pu3^!yE97uO&BJ5^*p$gDKqcB?-vP?^^CJaQ0?2C$FH_C8TQ& zsrG}A36db=gSgBn^>nCm43f<==*tWo32Dob>Yz)WBLUy*^N~fVw_x>uvzFs~qem@= zRva=e-)zYBP`z}01qxeUq4f5UH{;N@!bl{bu) z;wMge`|cB0gBzo{j`5M+m60!3sXB5L9n)V#-S8G#;wLe~i)|<(I_qXN;1H+sqlH49 z?*BbMW0dUOwNn{m2shKR_Ey!g*F|fl<)?uUpZHJY9CRfPSbKoAlp|xc8D|))-C68> znyJ5J*S7mKL9>D9Z??=j+E%aQ?rakakd57V68Z!J&Gu_IPyI{O_ccF9N=FCYW(0)a zInuu((8x8Qu6L?5;Ju5df5o_@_*x3vWK>8|eF!xp{`lJ)3d;3LalsE`g6F%5)UiVJ zB%+kxc3mDFTnzOX#i`WGrX<$P-uW}tQfea z7Iz(=nz$$qIHV&jE9hITX5>|{ElHfIN6-7X@mcLop5o?|O5LY0niDrsLCp4WZ3QL%RICZG9uLn&W}kcBdK} z_#EwoEv2+{mgY&qD_blx-IVVK&6A!@iI}zMRq8-Us&Cj;9t+H;WbOSXZ0{rQ?SS*c z^uCH?-*tCLfmhz3Uh{-LnF7Yr;d?bLGU8aGPkc=ru=FrQU*bUlmOjd}iufMOgSv)9 zKcey*3a>P(Q^c}G@I!?ddXMk~z-$#=9`Zq8%ZLBhbi~%>10M9QS{`y-Hze~mCnmm* z>W8!PLS}}vCW;TPrE`kSRcIP0e6u5W)k}Zm#k=dWacjRa^PHevmlx6C$;0&c3Y>*? z|5?KHqmbvBv8cPY_pLIkOdMOEV?zPtfQk^RM9NZA(`z&pULeXPRy=Z|&|#BTb#zQb zgV?g>kVOL0v`zv-9U+55LdUO;9lI{Qd;i(2DYFmBnpu3n`3|c>kBy|obuNMHYoO}L z?Vp{dX4$hVLsd)Hk#{1|(YfQ($ui8ZC_4@!6cJ|WK*MSW)@n%gL%2(tGjd42;**g; zkg2rTfX;btPli;wZDxWW1RWu7%1|B$d9B|j5Sddo1ppoycMW1!3>O)xQm!wp~ z67_7`F+e9*1OlL#M3z6&b|+WD@Y3Rm#D?#GPYdECuU4BNV~xmCDDbC1#>2o6iiLv4 z^DjMSgiW+E~ zOwd^^n~ICzIYHinoVb_j>6;1}7KVA>uX3y;3qfM8OB7(Yo}ZO=9m*9bUtTCMQ+_zv zUPV)v&;0DFJ>E;@12+uw;d++RoU{z6d_b&0j)Y!R+J5}Q{hMQAZugr-6%Mid8PZ7JkQ0w|2it^dvJ8tHuFy%Vs`EQvE2O4m=hw&rCpTnhyw%`SyG zvoe<6Q#G-(riKxx4(AYD?`Bu?4tfR-_B@VvS~z$jevR_;CHw{g7ATYam}>=h*{2)c z56j^LVbPZod%NtsVzeP5pvL1MfJI*h_NNK}?d=c^m3+bwtr2EF{**w7&bSkFc~h_! zCtE(>{~lYrPCq-5NEaUO^`i+Z-o04xJwSQ^tXyz@)zUkm68J4w!#@^cw6n=iSqyIgG@rx^HtY_Q%tcyBa zg#2xLV`|bmc338_9*mdzuErR=KY96O6Kt5o^Jerzi^A z2x`gaqEy%>F2Y2G1jLkgH<11!>W^fswMwhPG~$$Cz>}#ztI&@rKUnPPl^&a=EoX-V z)htAYP1XneH5GwgTT4|`FD}Rj?!nvz1PgQ9j!H9ma5ak>!EQ*0~w2T0s&f(0P zg4pAP+`z$E8F8Y+bMQZg=k(A#{k?VY>y|P_yC_u=jB_MCM$>r<}>EU%HO#6`rx}0 z)<_P%E59%>Iu2}k^y;3IVhn8d)IdbP|x!=XVevOc=!P$OQL+>-aN*E$tmBw3uuoGqrGcT)y;zJ$_h_c zn&Tb4HgBVts7~5GU=Zl^aS7wnzc@j#YA-aayB5V}9@jb~TQM1T?LnQq(rrR}Q-IuZ zDDT_1&0vNg@LzN4rer?27OYiX3>vl}NZVX%e$jCnh`i|@%>%g8G(!O?#|6?5N z>dq-RyEhq5lqA)GJ-rG(Wy*dYi`fdfx&K|SOmy=qDC)ZTAgfv_ropohma2v3U}$^; z5Muh&lfu4GmXykXFke*IlAQ0`ceeXa`GA*^tuDSqai*z)N+st0o)oEO+qdvn%Rk^+A?E{3XIF`yu1`9 z2`m^|N0ozi7nkE3*P206pJlq>FR{|OW#QojD0UdEaa~;p?B^nV&0He%YYl? z=aC^B4jLAh?)CFsmJCyHW?(VTWydt@Fh`AB0&yMCxG(s?+n3Ca(Tso|(_*8f>UTyY zrUky`AB%%IlIX04($kNQ@$ZUV=F3bPEPO2iXVNtj#cw99F)m*b!)L_%7MOr6X{b>s z{A4b#^9KEMu*Vgjg>!9WIJyNC4y}F<3Jxk=(=lKRzFjfKq?DU&ftl4RXH$ay{`L%0 zE1w;jI@Wi)w?NjBH&r#j7&T#;GP!=XJf$7|M$#Alc%=`qS<98Jyna5h9Y5t)h@`M2 zpOK9*fG}-W6L*f_@QJ{jamMV%3qn zOcD?+;^*{C`Z%m``H%1FF!k{rArgKkjsp5bK`k|hdB?>iZ0-Fspw!WB#6zfb#6Es6 z$OkXqcJ@oML_qzi#Y1Y8$pe_#?e5dB!pWGX{={x>Vhj;gHn#-j{^UK$mgit`!Y@f_ zFH;l48{R}J7!i&?BnA-Cm`0=7?f+vQAF{WvBGhlRhSPv`GwFpSC6>$PZaQ_kS%1GQcK`~+1#By(wpX7Q7;Pmb60g5@YXb)GXwM2I68y;>_qr! zBLkhV5O)ny z(#n&Mkzx+h>MMebSrgW2?c7+SYe~E^$vj_rBYW_chzNng8v^9BC4HD&1)Eah|9Jy~ zYigyK4HzCZEda|;KCIuVDXPK*pSpMA3xN3J9HCP`M%We}-Z#nKEerVYIp?|Q|D)^6 zJWOlTbbNHS8C-5CUq;*mVY zep!Z>aLleht-$w8z_BWZJF4LMaiQr;YCdifE!K343^-zzy&?T)Y^f^homb|5O zeyGkCG|emdGCRA}KqwO57G7-<;h!S;HZjVo6zW*kzF4bcT7-W;>Ep{xO}J6wr)!7lHb zodkv01?{1^*-I<21p#X!{=Kf<1P-c(1`g*_Df!ls=~efIh@c-X<>Bjd5lw;5!M!%2 z92ET`(!cS+0H(0!6eHiggc8qs_1rCV7D>4a&FQP(%x1HufE}9eZrOB0e#CAm*cCnS)xR@=C9Jv_$2- zrsrV2sj5L5|`)B;j0qgeXI?1~qDcPc_J=*RTt z<0%CMQqq{T(FG(_oQ&hy1mA=8tU+HGPUqi67j21vWnH_2wq4D}xnqD@rz)w)3YN4w z69jkmuN+c#YumJNR7q|rFp9)~A-92?!Q9htsz*)gdYiw9Na_Asxq#7I?xV8uLI}^g%EFxkAC*@lI9>mxO=? z>(#3SuxJ9a=K+Vg#r>ZG!G-1GA4LAaUew$rs`~Z0EXrBCwNuCVEX@?Z11lnEqvEDQ zJESRw$5W@nrZwVPAfh#A%FZOcavC56J@i_jRH#kg$qi=AMahWVbV@7Q3sz++4BJ;N zUM{4}oZk?U=2|^)7`WUP0T;bZi%5JKVaGyRdbbm~^lJ=%sg-624&D^fRex;!k21d+ zBE5pgl};tercS38q;M#ri{^#Yl}V*$SlvR%srR>G+YBZJ5zBLAdhSp|A4`!)LKMH3 z^{t2^hcf>#jyBw@1C4=9@fjW9odtgB5K#V;#;jkf{U-+s^qkh&8q}JMU7vJ(m`}KG z7g|TG(sXq04vTP2P?R@IrrfKnR7gB|?)I6$O2sd_>0rs{wj9+Ee_^m8V~aRhwUQa!kgo$2Md^nXoeDl(DY^oI%^6cYRRTh(l9TZ zTrm+vO8DyzFf)NKWVO&*NxTw%CrH~c`V0nqg1PxT>%$8U*22{`3Hp(&u9b~vd4{>( z?bO+`q|SRCz)T8}GOkv@C^EXKZerHiO|1oRtK|N^^u>SOpznMe`xcZs|f%CSf zok*u%~j=o zj>t8t%6VC+kBYzJG|4-r>mDis7FeEp#XT+;tM_;xM?XjQ9w;Rt!`et7F*3zdGCW!u zf*mL{plWM@GURWRp?*1*gjK|^3cIJ$VGAChSw{YQnbw$ym@|0m zn)gh_eSP>RX(|EE>Z9lzE_WG|hBe4d1YXx3xvi&n0Yv7sQ6O`kdgSDl?|rI+%`aU7 zZ}dH$$$BDtOJ9iFmDxFZ^kd_5a9KHAWI*{hDTy}b{n4Q0DvB;fX2akwr4WU>;O z3wm@rILh=J4Z}agg9^4edw&XFbOG^s@eKHHKKd`|OiXOvOU&xiA9Op+y&3uq`ni^( zOzX1Niq6+*f_hPlij`V@Wr~?Z{QWyHZ576@qRl$_@_|i)^n9@O8wnrHt|O4{5kR!awUBcuAuWes2LeVi@&{NF$P<1UtT!Ck5Wi2pS1a zwXY4hHOp|JpX>0yW`6sioMk4dnryk~%I?!V+;fy7Z}|lu$D33wn{~n&Cau=m zV8a|?W{Ct9uKGc!b7F9fiz*knY?KSo-VUQ1Rgw6R+??r&FTmQ;jgnhYQ z_;Ob0b}hsG(0yn6IR_s^x<=CMF3wH`av9UJb0dytv}Q3U9QiR8tDQWDR1{vfzP>*| z6tD}9KxhJgZym1{w0+QmS!IcNg7Q3pQPvf4KAZocDm@SLKdeV#HXp?vf(=X1Z%FG}! zRuFxlLaXFXtiHfu%4RPim)(?xUz?dt@SroM0|ie(2_tgZ0d}*D*zXx3hI_OW#}@=W zYbN(-84=5il_xw0%4{IDvNR6?Zhj0?zE;`l1^p%U7md@J2lYw}*J}A$G4RvC{MY`4 zV(x>Xd->h`yqzSQG`tk@GYwtOOM+;?W}Z_;Dq-OJpCw)dvu55-B)dDI&~CPAlq6@s z4Kvr>r&Ho30($-v9ZgNYMyINAPTEA+wOK`L@|j(ww!y&h=k!Dsl*{OLG5;X1J35(Y zldg-m@RprDl+k+2$LGK-^t~22U`wgu9ad=1E{F0wvJ_^GV(C5ga}BdZS2jV-eA%@8)QlIpD8XN*l;cP z_@p^6qgvV%a44De>8`>obOZaPW>+_NZp{k=19PQwvY1ykR=8DgDcLWPUUoy%+yU!- z^66{+fEbBEnd%P%%6_JjDTIum#J9L$+r^k~( z*eIGA*i0q#HPO!p#~pkJo@~zzGbdBxL}mrFjROv5*drwASJuzl25H{)hvSn+ z%gfElj?3GrC>qMTud3#Cd=|3>xOgN2VvBQ}NncqhlT3j|6wTUOw05w6tDWc)>y4_3o&7r3g20GI@CC&s@2)g0~MZDQNIR z1-a|v&9&5wo?39;NuU`~{HyeUdz=zsCaFNtV#hp1x|lUc*Y67RfcS4~dc=1+w2uw{ z^25wMic{^4)$DH%*hmoD(NAu>^$RuBkvX zZ0Mgp$#%H&O8Qs&vSj{i&PY#IrbZj02jbXgwlJ)(6nj5*fP>)R^Z zMF6D&Y1%s5hGsN06^?KYZq;{`(SJE{1b}HFZYAnj0*SGR=x{i;^}4EC3Hx|AK}_r& zo6lAQr=Qh6Z_lC3K;(x|*w4ycYoVU*UHy{VW)oeRvjx#No_u4nhAbXr zZ2hMaRg^Tz|DIJI_rciS{%SBh;2k17k%s%%KGxFN+a))P!^CY z-3|yv`_+f!#GGAFX0ji0Vs2LZkZl@z?&Z>rzn8aLA{bZyxQlKP2iw-X!RCh{E)=lCgdDaxA#m# z&fTc?750$aZk_&;pa$rhMiS||yppDZei1!1AZAsB{+5BQbg&qyya-{c69 zO5R7rH=N%I{VqR|aECj6%6e&*%NI(0bu|w4 zyqhZ_6JZ6+`_;(eXQ%_<=**Bko^(I^G5yrhSE_!C2K9T?$EwT5g(lOj5qppOz8S3M3A~aW6T&+h)>_~d40kyuJeDjRfy`aU2B}F-z)zUqLj8z#B z7V4B(>Wj@}?&a~X%{g3xMa;y|>sShfL9T*&GZGed zmAy6(rk}BLLB!~G=G%4FL}Ebg-HZ!(o#v)d4@Jl+8d;n6?Li17mxiL#rz24XKgAY@ z$c6S4UXcOkuGQ$duV=Aw!DN#+bLA1Jj?=+U=BDTBzNuQS6;EXs^M9I(kGXzlee9b= zJWbOW!*9~lUOZMiKO1yo8Jdka+ z)DIc}B_7BW%fC10R3AkT%R=)vi6(qk2BlTK-w7_ptl(*s$nPED6lPhWeVR@~mKb&yo`PNj!>$;Le`zJ>5 zQlq3*6uK`sQKkbcF{j(`IO3eFh@~N!4nxpS(CNl3A#hN>lJkh&=Y+DZvrJ3Sf62_j z>?cRYDu}(bkv@@&%jmqTTSeolPQ-5Nvj*lEQ_QPb!ja-xq42zk%M&rR&zd7Q_nY3` zAw-IKB=zC0>h@N+t7(nBB#Et}Jm0>cmz=3$d?kgF-@V&6b!#^G5crEM;H~%>U(j`2 ziV1I6(<6^I*E@!A2EqCrt5=#!n^(Eu4)VjHbi>K&6gp)!p{~zs3!^J@eH=##dAp+C zn`2OM@b?|yKwAy&nw&^$i&mT+hngLBm0IL`%Ht)+eOYags6##Ygux_I<)Cq`3$60( zKTCI`AxqfPmd||25s`tEz0JC3s-3*{;TzY+LS=`J}|t zP;WgJ7DT>Gp)r3r%|3hos-RddW-|NWPg>;gt}&Tz#KtXzIz5wcp-J?hS4>c@DZh^G zeZfQQTwy>cadD^GrEtyr*=GV?-GI10K^qB4EmgYJ;ZmPZ+Tn~bp&ayR80BiMu1lha zi$7Wma}3!>nSa}m+P)F54}(R-vubpgGUZ-5EW7ck^ThCl*SHuHve%_eg!kIfJuM%T znu}E1NKvT*y9-NX_K@wNNe!uw?`jfrUun$s$Frq;bKj8VIX}XrQV+Vk?&Jj!9~8x_ z-2nFRpL~r8N}~$(6o-2uNgtAk^Fx#_9nJ=l)Bu&Sy86RlFy-FSte$k=F04nV=uRyO zDxms2w2SR&R;n)j3(VZ6NI1Zx?(u2GslFgkrWMletMWHCFu9LR? zPIC(%{Mi)C88~@skvw`NjJ=0m;22QjT7OY0yr(sLZsXAa$(fnBiYl1g7baCRT-B>Q zqKCJ&D)zW@=^o5U`K*=8$A>jR|6}DxSar6iXMDI{~lp|I)x?)23GHtI4fs z@;r_3b2mK2gxci&lH7L-8@GC+>I8c13YB(eR_(ccD$#HE?cld=sziOz6Dj!PYpvA} zA7|>1CmDggaP`OUjN@~8MEJ%~gw7mP826;rqjqJwM$J&r^Ii;LH*}`Fc8T@ek;@fVMjbOq~g@e;C{J;>6jhDuXZ}(pD4`0`s zN`*y64y)g`@^8Yx3MN^fUIRF%H}e4GCl0xCJK%&X&NJ}O8fA9q0GxMw*&^Jx3WXc$ zt54O-3+HbJ5Qp|-U*A-fWtr@RZV-<1tcExQj{xso9Q6bQMBJpK3Itc~)N6e&L7HA3 znI3Nt@1K3Ft>XRm&YO_!t6d(Bo+%jFcyhusa8W|WV%VHM-T5vHR_+5wCuFXge0Es)}>3|r{PeHXRU{F%5> z6DM1VRf(2p(}(hQyn(zuX@g_Ow{ncGSwMYwmtt0z=5+eCw}_F#rXipE?m@CpNE0u2 zHAnEsx%MWL;CB1@fK}peiV5K}T`z`E~i0nQe00 z@u?kRMl8?gtxVmY->~f3i4m@aLD^j#`4hq5rSEkt@p%mH>oO-BsTRxDr(6FMe^miC3FgShG zM|-UQcyZ)IIZ;RQQ}eR8$4uMvaGj(rU6TVRVb8u6TSwT)?s!H^(_1jYKe|RRfhqzX zrUzKn>0`{=?76``DpouWE4CVC%jwixun44^@3u5SI*ytHFWUFdOwC#PdF-v%$E?_5jDB^=)Tkt9UBB0qXhk5jn6V)veyTHOn^ z`|DZXBs=(q&!2lg6IBYXc~uD)g;tyGzdn^+SvODeN{IfcP0e*MXecR8r9f9zp4?l& zg-f?i66I{38d8On8hw(P46V1YX8EtY1hgoumSz&;-1Un5Q|C6TDfUz84?S5!?}e~i z7~wUloHEq9&qz@+mBgGMEbq--&?i7Vg7!K1YQ)kwfAQWQof{cb2s~!EgoGwA!VF?L ze6M+CU6*x~FhuCsY1qR(yi>}My=EgBMCOreF(Y$9TS_ddAI6{541GqQe^7BS+{BtG zba9MOBsuwXFV#SM&;Cbqa842W&NTQex$LqS^*~`mht&@1?X|k)2@UCPi~QCtmyPLR zljeq1D!}rnQ9sh`q$}xYliX)KcyScmKu273zjaZr^E28n%<1ia35X= z`M-}zS24WyMk2v%NtMY`gtbHs+7`|VuxDeRZb(}#nh1s4QqhI-2X%5>HFNlpZZNu( zWhr^bw0)oHO;M&VV&lgYbNG-A(YJ_99U#A)RKA230`K<44B?`sm_EuyD!Sptq?DLt zW^oNSv7obq69>~IEbY=?UOt8NYq>J9NkwyDEVMq6Dq9|OeD(^+_hkq@TB;Z5D38XT zB600;$n6CPs#?r)bogi;j##Th05yw^PxnvcfTN>A8b+c|oea*+3cKH%?dFMZEI$Ut zYe6Zgm{Lvh+Z2gNPoNHf_*H+&VV%+o_k+iqzD z?!xM(_1o)^amXO!S8xyEAGJSnHsEat0q?esjF4TbuM4$nZN=I4O6+SpJ?A&!HwF$@ z8_QTI1!xl~{4|c57-Y5PoyPYzw$P-&tBlhlWQI6~SuvAzk)hvQXKl(eM6!C~^b9i5 zvTMyDC6&Z~!vNLQBjk1Z!!*Kg_H%jdL^HcTR4S?UST~vMinw&X)kzF08XG>lgiu$6 zE?v!I=zh7-_)xG^sHrk>l&vv;Yxe4YhDvZ1W0#g`W9U86-+5X)Um3e2*WsIAAzqh` z{`BSBaA?i@;ozkBdl?HljFWq6_YaPZl?1U6AAE01_#%qd=q(z& zf&$o9V1?3xqpvxWTmy}=h{V2`K0{vpx2;Z_ulI}ityW^Y+!|0uRsbjOH&%o=aKBp; z6JsaKVOiI{Y$coz@QAWgoR%N{aryD=KE=WX?NrmIt7*LRz{IUYfsTqceFPnp4^3Ts zvt%#6{^85lso>+^Tl_Z&pM2(r<}@$oh#o3gnz_xOKO$e0LN<_*h-$~3k(ZJO1d-a< zv0^6)p4|ZP{X~eI`)+*{M@Mi@IJnuPVnR2nKiF;sq2B(Z2Wop$OLm*f#x(!|79fBu zsdLQB$kQ!T~reJwX>(WhPjssulL+>;2bX82qk5qQW z)fXZuVB|FyDqQgqrjga zs@;rOUN|HGAJkQv>@C4}e|-zhJ=JP$-@bOpk* z90Ez%P9ag9YTqi}YI7omRLKj4S0OGrx3>;RHcKS~NolyS=iTi0P3}DJ-U)u(4$hgp zj0g%`x%-6B939Qhh0E!${wP5wIw31<3il4YIn9ZAw8sgB+}zg@?@!Mq@BT;?>^c%| zFo7&!SqoT3n&bbj;nV#2jQ}R;=K7eaRKrJUy24Do-O9rV^|xV-LBx_u*p9o!{!iiv zg<(TjHm_)I`zDF@J-w#6ytDnOk(5)lZl!N>`@?E=)0_Jbj21}qZKppLs>fHk#(Z8F zzFo&hak3=+<5mUhx3PWSwElrw z4LIkA{zdZ!nu*QR47iwmn8+yKA?6$$<9dqW)@AsA1Rx*6w`c?;iNY?_Wu zG5n%OG_nRW_?&NHYs1FQj#vj>m4Pv9s|Rp6rpP~eHAgvgs6^`aiq6$auyp17O6IfC zv-S4ra#*kKT{empAj9-eWgWuK^!OA#|E@MNAR0?^(vJEYS#41FQKLL zIk<7^Q8;rev98V(*M1QLxkp1kH)Rl?em&TYCzHPWKOh$rj+L7qkLggZcrBCh#t?fj zSAL=|UTXpbL`l*T*{1Voca^& z97pJrR^2O69S8OtY7!In9&QaSRHEhUuI(sT(GrpeslhGhJdLRq6RnbO9;6oTjKLp#zhxcYb!%7xpw#HyYvQQ{g;Pd zA@2`nC9IvwO=%%oO5P zl`AeD@prium${LjDqBLfRI-~}tb>EDor*F1k?LBs2XoZV(9bC$r;Z!IqrUA_QmXRLb&uGlt@{+%i?4^{45&zh(Rbwh@tz_TL01hI6xl|* zATEKtnGJpo_N)E076Lfrf2lGZH;fMoNrE|bvNal~Ch-*P;Pmstb?-h|F0O5T|HV?PQH8pe+Rdl-RCM4&~CPD{YQCc6W7b25WEf%nCDc>oudaByq{-~ z4;&T;yO^i6&)xHmSxYx)flN8mEqFc*v zbOIcm{z%t}T}!Q1aQ^-m?;U^O@gp?Gc^#UrGWN`gN#tI9IlMt({O-vJVUDyhtQcrp z_m{d0R)}0^BBB6I}cKn=4`Y9Q{@I zhQ`Lsez+O8GAaa>$G6>K|#Du&?vNfwc2r_+!&U#-oK7N9jkW>+|#3q?1zfHHW=w7MklMM=K``%3+^Ca9bF=lr#-$ zvp)A88@IRFLE=72ym6N1e-~KfhF8WPI$*GTI5}V`tmGSLC*?_DFlv$kR)Otv ze}>-v6oQHeAF--ogDV8(uU)EHcTl%uvEZ6#yr|P_Fua3|E?Emo<~%*I8~ZZoeZMr; zn5~hNy9_B~RBHT1QYmMAWodvCAx{Tv@TCmu^9Z1vlrHwJ&}XpApmWMq&y%h3w9GMT zfXl7>`Gihwz)`jKVcBXb9MXTJ3!#`_piS-aW86Ctm{;7d!E4WDmH_Fb2!*XBfn%g*4$-lGuLpa4MLuoM^oO&j-Z^!Aw59jpwuKG*x&=IDa zM2sg0`wV?l1caG$@8Q`BuDNQ?c~*Fxk(MskMkS5MS_}t8&W=B8pv4?#-m`FPk8Hjn z5V5Q7*r}xxz!zBb79;Rx{X84;&R$h?f5imo-SQFP%Qx1XCnmtmF$Q6jeQ`1zYtERL z^*G3eQkyWSka=AN7~}DO;}2DZD@=~`RT79PY>iNv2;-z3s8y#HiyG9xUb?&Ox7?26$UPuXHJ|uuu4&<=rSHTt$pGZ8eVGv_9AACWKN|w@gau>dQp~ZRPbm1cWftFTW{s&SMY%l(VwrLZZ zI;>kZhiak|PW~Oi3zLQi5GiW!z~e)E->qc_y^=TB*LlT>Uq3VyvNe7_7Y*kRRUGrP zmL_!mXgb6;1gg$5DT<6|%=MEa+vM%g?6|6yo0i&_rFL7AT@iyxHgR@Tl|!!#&J&xD zPj6}H(IEXgMB`17ZEEPXXHaKG0^(o9fMmt2!YKe(#CYXr6X15K={36WWl+pc+!OM} z!YXiMTjXfj^uwSgsK8Af{x4ffx_yH{;&OG`xmUrMNeT2MQRILlKH6b7v^hMW7qs4g zM7Er#a;IpW=SAK)=nxC9`K8<2mdnHTlxhlPF)-Sg5S-VMu>n+2fNZI8N2B< z0r4VC+JZm+VVaKuJ0x3N@1ddW?{KM zL2ydp-t`bM`MtP>+6Tn%=nX!a4FoAkbd%Y6(eWs1*cAw^J{$i-365#pd_7fHh8v^< z)-iH(sE=>-_TU2|%a|Rbhe7$)>8U#;b*tGzj-WGAH-dn3z|k=z^R5%?cfw*R$F8~x zGJcbK1p|i%6UPUs4SqR1jkY(@kXP%WMq^g?nKa z^&Q{uFoJ1J6K+PA0uto1STuSQVkZ314U+|H2RQeF--^Gxw?%|ra1=iz&3$>r)q34U zghJsJ5X-F_h+7EcefLZ>LuCDY^y#}#SIe{kw@{PE`sxnhp0et%JcSN_4@$7 zf9tfldEgv0*XNltQT#lDkle6kvnMg}=n7GD?4@^usmR+;-ZE|prs#X2ksgZAnI_Gh;`eW${F&5Vyt4=~ZHjt|@fYk*A47QF*Qp;rqx{YqXKLE2724QC2jz!RT6`}xaWMx`V2*PDJDmOP0EM|O~uM~(pFkj_CMYbh0p>(NQ$_O{J^%DUe9Gsi%EmCh*4ATQNn{H<0?v7YOeE^PPOI zUiC5qm>zfojJXqbDo(xUa$I^qxUTB2$|kmThAp6Lj5(k(8vxh)raQ1T=2>#DE;L0S zY%YgMD{N}M1N%V{ZsFzkURpaooGUtVRFJ_A56_Pcx93~(TZ46ZU1ko|RwKzSBl(a3 zJWXNtj_9dR07tsk>e7Jb%}M<3kL6M1xsEU&`;jhmwikELxwT?OsVb89Is3R<(&dP} z`2DVIjYjvUhWtuWf8~*L@*v}8uqSH^vAaI&NVn(80h4%J$TWD;OW+}nm{ZKWc5VCV z>0b#eK=I11DzAcro?fWbBLlufFqH!V0-(n!`*Y}zJNH91_=e^dKV_<9WW0=IvPMl#%1vj#d zhq3Ou{n6RE=DMXx)Yw>oE66M{BD+;L?L*1O`d5@vvyLI|%z;l^?8)tY6QiT`pi#N* zqX(qd`qs@S*ekt%uH)uTPIu5qg zQ%eMWNiy2}i0Z=$CDor?)ZoiU z^%M>me9E)V8%6dkFXEd1`Go3!?q0!1qhI%KnUKJVG1 zv)V?CZO$1Q5P&SjUn}eIR}PBxulF_;J=10FIUnX2ZOlEQds_nK%LVVa?C2siU;kO`V6xPPp%nUmXo4j=3_tEdBvO$(cMd z-+T1Q1`c0v2ozGcwaGL7x^A&$u&d?E)CZ_42#z%&<9zKM4}s9;(1@xlxg?;k@KL#~ za&4XW24ekpxg`=9O^=Vl8;*`=$p-~ShIST;f#PYrd%veEiqt&jOyowRjS;@pf}B6P~Pnc0bCBy&t$#5 zxddATN?M7^|0~n+cYsFDw0RFhuAvlcLlqZ0)jRT-Jp-|WzzC_TfpqRw*Md;;J#-_M z3Ilp}!^u!5=7*D}GoifhQ@gS8WZ^(2s%0%5@kWBA@jHb6hp6$n?w^EuvJyTKHG=!) z`!1Vy9PxRJ$lRV$17BIhd96t*B;@rp_FJMmoj2qD%%Q=cfV%Y%tq?M?nuYh#S%YXA(2I0UZ?UXSP zZC)`xDE4}@g7yJ?Y9<`QeYl7ac9Ie=B_a z8@ms~Z+%qu^MN+Tjkxv0zh?4xzA#m|{>JSJ&dXj(%G*+}sc35lxi!l9}oI;SCd$VK%Gr40zQUvKO%W-TzxI&JJD1)@y%L z#3iNo14zH)w$Try%3c{gCWpdm?Wsc^*1zHqqd3v!~I-g~g$>)th)-$VaXuJu@3UDx%{Cg6DN365tR5J?j49hAC;P0eSE zkfsYz$)1mjSe7+UfS^J*wSR~JmWt4y<2i|oV>&PXdIJw{_;D3&w?VI#NY(_M(w(~X zYyAIZ%o;aL4q{|S;>dsrN)lnyFFxKnmG3LWNWG19@lT1E5spZ``pOWgL%Yr^Z11m4%nc}j^GI5Pk&rTc#KdJ zpgi0BrLI3Y=xa_6bI%d;(;%uNv$HZUHxW??Zk%M?E04U!*l-ja=j6uutZdygCBrZY zGm(_d17fOYa3?u8<2jbvbcr5&Nc4VxRuD?@3tixMN`M*ATI3}Y$(kz6dP^dp48%Mf zn&z0tnCb_cl!C~Yw|lor>S3yHc~4WZ)tZ5{*H zmr0+&z_znrvw#4{6Yxowy^4D&g`#_4q2C#dv@am>g)v6dZ5t?sjXTsz;lhchdgjHD zFfCb%ybi?voY+D!jhYvi#{e!i4AR@ za6sdA3s=Nk5n4(u;_RK%ROUZgPusEZE;G^>RrCfVyk}iz?}~$J_A=5Kj?ROSt4lKt z;WUw?n}s0{0btG@(k>5oCuPdjY=fkWN)120E%!Ui^Ke~kMfud+vnyi+5Z}_;I;^X6 zJRg}#sXAu5)0#Xa_hX=w9!aCed%a#;ALN*xW0)gGYm&HQO$ISP8vZC0hU^<{(x+Le z?RLy3$8~FkV%_~SOptjA+{mQ%t@luclC@`#_2)KO5+--qdO}hcbsyr#ymwfDb8_y_ zVqb{QXj3@tCERB@|yFHDhIurDS~kV?XN+BdQF8CLkQkW(n%r&_9@nGGC9 z=+^ZcI8W052=4+zIm%2YT%o?B5)E!2IIM~qrp_?iuiCn827M@j@Ca$2f;Zxlb~rd% zN!(A!wKqWx7SAc%+eNC-e`E#rjkYlFjV#O1f#>Lqnin!jqv>PPpF-t+5ISiziv*eL z)0ydc^AcKy`sZGabsvQ^)*l+J;Aoejqy>N8x|we_U(0MDEKyE%C_Iigw3fK>`LCFM}PE+U|_ zDuLl433iP3Z^0U;vd6^xwG2z)2eh2(r-T9XhfKQ!|C$*h1PSbZ@7Njq|Qnv?Uqu?GX&@%T`)Xfkd6xg`0(vh|(xzl4YhCr7pW zkB|H1+98~ik=(K5b7Fa6HJl8rbvnt)-WJM!Hemj|;ahqE>~b()tJCC>oWUe(=^aw# z&8P ziPq1fdrw#;O#F;1$#qzUj@R4(on_f&2NJW@2+PCsSOWt#s!@0SPu14o+vi8ejCT+D z5EwEQ6G?aO0`|90YOA+5a%@kD=|@HR4$}-(yy6yG`}P%dJdG7A#Q3FwEi+0BV^0Z& zvHFb@a+YmIyW%cfp|(B8T>FkoI@0cM#2wpoC$N6`>JjzLwO;U8VG7ril`VcP;G8Ej zf<0Diq!M3cl;I+N>2%G)DeU{Jol2-nE}2x?6GD8tCtY04ZMc7c(0OorpSpTLBf)cN z##vJiLJiH4rZ@YaY>6Ip`mI4$fn|UOGrmr^a1UO$%WhGEg5yyO z2YX>m9Hy5fk-Ca_&7d>7Ud|zQ(4d>5XLV2A92f5oHr5)A4Kdb|WuqQ?aN`6WKj)S? zYk3J+W_@Z?0%8=k*`$jY9CxG(P7*cOh!z_lY`S79tOwDjVFZw7uTw{1Df%liejP0+QlX zPO2hrk;{(KUK(*5^z42)`Dklv5=24KjdEAalNJJfd)sK`+QWTHDFi(VWHT z%e^vTRlA7DQqqQ1%!X3(HAD--$9Dz73s#d>kLiE@B^aJajtlmho4VD4gDH0LIo1TH zH-3Pu2YsjD59&y(p@ux<7LvBUwT4LP){~cFY>{V8f~EnNrZ@P|r2oo!QZORDfrzM` z)bQ*Uia|%yU`mJR_wq)(fi*zI{xwHzc${eYEN3obw%B)6UX=qs!)=HGnG45q5Pv2% z8$H4Lvlk;IZJ?uA=B=%}9i02C&}BEXv<>SIJh6X&{>C`qtxQLJyB*eme_n*fIyLX( zr%#>Olc#qSYmDh;_*O3|xo@!olItG-xLh}sBU-x|diXv)&?vfl+CO*ge2+8cfdo~eKuH#XQyJ<1eD*PcH|gNbD-D+e528-Hnd>>;vea@CqP+?D zA(aGC@&9tbBz3mB6&+8(x_+k5G;zKV#6z@ngHiu_X`X^5E7XMDJRYG&O1*lhd1|H9 zy3s6hHbRy*lNFMyPL?f((69#$Z7s$=2scb7e}3V8@p)szh3LNdC+21&Unjl4N~>Rn zMa>oD@Q2uL_HXen?#`Bt=Or9E+>swOc4=?O_iMg+ABxP2hu*I)V%zuNNEZSXA z6RW(*AXoCIg2$DZ?%md&IdjlO%=`96CeGv-%`>M{9bO>ec!m%4=4BneuXgGM<;IEG z%v5|gyjqYrMJ1kry(QGAp%t-L#yS*fgwODh7p?RU-zn}jZRpVsxwauE9mnK)AJ6Y= z32UKEeNF!~fUYs*1wT@ouYeof{0wON#o;^Y4m?)F4}NCvR6H#c&Qk25@3~}rj@|mE zG@6t-G5vUZ=bu2_r+!Az0hqZX`bXT+u z`Ok7g7bEAmP$vIkECD>JI6?GmJ?!aj`i1~Geg4ZkOn}`K$L`0Ybb}b{`RPxu1LSo{ z3?Dfa?)Kn)M=(t;xOoNpft{(`E+aTkL^%mr<4Z5{~ZPPb!#u6(KYLU;3WRSe)gg)*&dysGitO) z$SyZuTf6;N(7OCy=nNI(pLXk%g1|}dMsrO{c_Ur;u4M`_< zlD;V)At4eaS@FzRzV(~T5|=FS?|kDera1s+B`;;{8^IbGjNnZzBdIEX&kGS+Cg!~o z?;h-f3OlyzovESO?r4}je$zkpel{}%h_z`D`IkQMh7vpld&{qR?#ZwY(K;<2Cf(%$ z&rx?Lm>1n;$hFm&id9Z)k#Z#|Uti1?Gv_G`QB2ag)f#T7P^Y8gnff}OyhepKcaT7U zvmxMkI+T-HLJSZvx1Xu^?G~ZuN-l{@1rAT$Tl}7o>`x2O&lRp8v73aVb`o|_y7pQs z4d%&P=+yV@-7O?QfE*C(`o99kJLw$-usr$L?*T}vQY*bzm7?VQ#cq@YhE;huUM zL!;)KXq(KZ)k%w&%NQqo=Wr+}s2LEwgh?ZsIDcL5+RTJqx7(Y#VfacnkH2|LHW5@G zRGrs)cujs?hdvY9vnwV$a0~gPMSV?*o+(A=pNZ;3jA!=bVWo6jdg!xPE%r(_Moyss zIp|1;qS#4x?EN;%;Kar7ic=vY`}_xR3*j^e>5Y#XWlu4D)fc-uGw(DyEfAqEsx7Vq z1xSVh!Q$l{0%rGD6Pt^5ajso9yDvZY9{|p{-@>8nurzqmlhUP~`BS8_x%hh~W;aqW zHSNJ=hW1P*ta5iB=~$oELZxo?*Ga}|X#rxRzjWcn0DX3aLitttB!`7URzEN5{Y~1V z*Q+=#4_5WmarC=IA1CuOj1J7)EuZi)*M;aguo(Q8IcA2&!_oHgGQ^kDf>}y#zUt=5 zw8hWIT70FSuAzMe-I4yaX^)v@N1NZ-+4e7pOt5>3wM=y_N!E;gB{1r5eWsDukF`KL zxRjFWQE0?cK~&dgT%r8szRTbi5(wC~-+;t-S~&)BB=y*FNXz2_aZOG(+{!6#Z5x*! zO?9kfn+()e_8?C{);!^_so7@>i_3o ze_8ckC7gdW`zlSZtzew`@9%*-&%aPF{QeQ-e`3)8w1Ztq_&WygKm9=}{vG=EN3;L8 z9E{7=q4C)_UFGG@9EKymcPo1UCplu_4iYc6i9DRjykPOP*Yc%ZHxx?0A@4ayIAqEfNnnY;CocV~c zWDjP0pL+I=9EOrBMSqWbi#6pis3dMW2n(KyP2c0p7=*SQvG?1=XQla$8xe2Sn4MB+ z)MPwHo9u+T;ms$c8@wTLb<_rNVk0=x`!-G|6r}ioO;T8lRS!GyO0F zu^t)$&TdC#urz{T@z#&IFc6wYb8T)icwD+t{Brgq5z8icsC367Z3TiAf6w7_tI!bF z2j7SX%YwPh?Z~N~9cnpBs!xWc7o<=J)l9JDAX0z#W<9Vg1+_rfX6Kjv(B2g^a4J9c zUr%Mw_{F(A0cMu|vZL|uzAw&Y@X+@Ij%;Yc^>;^p^q;WnZ`l={zxsPE0MwG2)2v z52!=mwt_EKfCk_CT=2075Gy|(2OjqcQ3hIr2GszbMTMkwM5qIcC}?HTDBcTQM+H@% z+oV4I-}P7(4N15WhWh_L?&4u^wSOoAIxqy1_O@UiS_8=$+Sph3K(&dXUD1muOVCe9 zhIzp7IOYX45W|2Kx6RFJeQ5^Hs7LbZk-)ue-&qj}!8Wc7SjK%3|FYbKL8v60^ANnW z+k)PJhL&e#m72Sfeu%I+*uV??qjd#L{Ndj?Jop@UCcrCzracLD6_Xb2E0``Yg&W%Ju=${Lg8NJR z{N*nMFGOC9c>uNG0JFYXg^}?D`FRUo2u`?hsOTUx9N6Pte|YpojMK{hqOyaWZ1j)A z@a%Qs^CQsp)#BwLJwF8g6u_)qUs|z?r@`X<#f7Z(kaP}gYOQ!M_xbs#9}|=2Tt6hw e2X{8-`~S>S8`ZRA?rmAg00f?{elF{r5}E*n8K##2 From 2330672cb8db3c13aa4331540e355341b9f50911 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:45 -0500 Subject: [PATCH 207/577] Delete Apple2.png --- Snakebird Images/Apple2.png | Bin 21375 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/Apple2.png diff --git a/Snakebird Images/Apple2.png b/Snakebird Images/Apple2.png deleted file mode 100644 index 0e5a1a4239354d71c5905142908453912eccc8ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21375 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 From ba58aed357f6e644b95c62a594498e32292d67ad Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:46 -0500 Subject: [PATCH 208/577] Delete Apple.png --- Snakebird Images/Apple.png | Bin 27977 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/Apple.png diff --git a/Snakebird Images/Apple.png b/Snakebird Images/Apple.png deleted file mode 100644 index d674834a6bbddd661b4aa12cc9657c61c8db5ae7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 27977 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 z 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 Date: Mon, 10 Feb 2020 15:26:51 -0500 Subject: [PATCH 209/577] Delete Slice.png --- Snakebird Images/Slice.png | Bin 88690 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/Slice.png diff --git a/Snakebird Images/Slice.png b/Snakebird Images/Slice.png deleted file mode 100644 index 4786f1e4108d91a5add217898325760f7bcd75fc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88690 zcmYIPby!v1)1|v4q`O<`<^s~)9n#&6#HG7K=@bN|yF(C=?rx-0I=_Ry{=Pr-;X&`Y zd(WP|X3d&)B9s&)QIQCcARr)6rKR4fKtMogz5GFd1AfzP{&5Kcf(%0Xors#J!C@A> zC(-of)#|+dWwmunqHU9hE=#qkZYp6YjHoo_Tx~E2!UO69`E4;qG*)M-PZxF=0U7qV z{F{&FWPRAz_GQho8dcu9MB*HXjL(CmM+q^4igx|b_Ct>?dQ0@*+Mx``=PdDWQCJ6k^>Q z16e|-hT#h%FpZoP6-9~l8XJUa@5ZCm7xy152SepTP?^Lkf9L+)P$vu@DOj*UKY0rY zX<_cp>}IR1%aziPM_lk7l9Sr|Val}UIWAsg;r?EI-KH|u3p2g)1O5Ws$u6;*O1>;?fjW{v; zW}v1fs^DsPXwcdFTtU+(6!mL)eL*Y9-y<=Cf@hAr`zi1oO`Cl@IMtU4Wh9+Ux&vWbDvVqZvWIA&*>N@Z#$r?#%Oq*2oo7d7i={~wnEDCBDeixtfCV4b_?dD_ ze%ed3 z5M174+P&aivwgC6z@?6KG>6V_0{s)6JEZvgzvE$qYT41t-UxJoBvYNw_=q;R5}w^h zUmWa}SYxZIIooFpEqgJ({`Bvr-q3@IU05?H23%D!gn!o_#=yzmLZIy&(JOxVpqJQe z|JIVLl7okLiTZ!ZNm1!L^HnLS$%w%8RsjOnCUxkzE8i?vA@$U!toK|`Q^C^$`e#s2 zXWaiT{#Te-3zpq+Y^qhyW2vhOD($QK!fr< z!sJE<4z6k|``^OxWIzT8s^xZ1a=L>hMXw(3FA|3$ou(%S(TTbuJcK~1G5&MxY+IBp zA01>EW0uCJze~<{vRz1m;Vu3_XJ}_tuS{Rj z_#@c&P&~0{`ZK~3zxVAg0@9ZAvRMG*%8u3s{zY9$G1q85(C_oy=`EsaA1gvQ3VPtw z)lS=!E#kSs2WV8Y?EunXBL&ZrTK)!k!`dS0$Nk6Os9co~E{2{O|I%H6BEHRf zX0EcZu%p)^`o4(1b7S12&Gnun^KMO*=U`uuKu> zrf2itVvL}&vHG>y9lYN?3(4AA75tDkulcd+I=|grrMW6{+f|VJ%+)*)k33AX*B~!% zmgAa&$w%T4I)3W);U9j;t?@(M+WdMJu$~$-o5>4;)BiYhj99$CNvnK1D8W-&`be#I zQ;In8pd4q%lDdX&t)H!Adymgm`C;>i1N(o#KbF#o>!FAuy_?3>!}We>qEblu%#OOo zhwV%LXou*y#p0T+<;9khd`<#cRuI)F8eN1pBQN968^qg29pFhY{T2UvQdDObynhxR zCeH7SU@NR=64NNuv;}GNYf}aJIyXAcZ96sG%+n|(@&Fc9gmhFUMFle9e^sl~2*#bfEr^e0^xsY>xFSBBWFjqkcAUCMT?GNPIcFvD=EC0K)x|3Wwx4tiQ>+9Q{i zey%KvdrTPEn3osfROP*VdY$~C4T~l0i~&)<2!n%A%NqEqpa0;%0_yhQwccx?lIMw! z$~_XFn7WBHS9Qh3=6Sa|E@<{6Wl$77i$%v+*0Mt&`ja8X<}e5dW)} z7_w_~&9LkgKd4w6&<+()xqfm-*U9ryFzcAM#s=ep z<~q-z2s*m|twR>7<@FQAAi<(dsIT)v;us0y+x8`FHTF>x2ixwZHh41rmB%+GR->|@rb_7#UQyI-aLvryC6j; z_eHdR`99iKvA&!Gv9eir3D(zyS_GtO$Jzfdg%;*~b|mZdOvR{}(-#vOnb)H~S3D;g z(k=F7WfJa}Y%G~7-UzG{vt50n-V0Se!$NoGdU=Mm0`dPJ1vHe`!O4x))EM|@ekeMA zz8hN$?WAzarA_AT7IGs&46a%l)dMpNkF|P*y0%}u?+K#dHjuvp7QKr9f`B1o^c;;3 z&YRq{Sm=w@CYWi^%r_V~BxVkLC;8jJlh~~onf#}-WSq_24rb-5ZGr=j9=5Nexkjq$ zWEYJ42wW=Y;}Xt4Bv(W{^f|4+IqhE~++a;_q?@ykI;}g5DcsDKnA~-$iWfg9=(br{$U{o~r?4*4|C!KvkmB0o^-EMp9>`89|G~?V|e&SEL?Cn)A|YHMpetL8c}y)c_t|AE30M!x~?$;58nW7@ko{Dge< zdBSl*$HPkxC;L?qe+*K=t>6zPepVMNBWt}cg-?3xe}%7Bl+59%)h1t(mbC`$cy*Q( zDB{i1)3CHk@pa>@-zD{{A0W2kd$YP;60w*zI>+QcbY6o6_k8MzLO?;yvdZDHm$p<9 z&FlbDxh7fl#5a1Q!d=9jz$Zd6^us%@42OPx!loaqZCbWQUwGd?F#QWX4$Kwnr)hpR znhp2+sS9Bkab2+sCZ7W1bYdYLO||IO9YZk_vy`)q0?gMfnO*2NEx1vrU(w=lg#R#U zfMSCL!AmJM5}{NyPrQDEHwSWHaAahX|`FM*;@z-heuCaHI+$TRsv4RSG;Kayrp6}2lJ zu599VnJRD_uVx8ec=4Bl(Wv)-gIIv@q570U_M~y^laq-gbJXr?ahU1xg>n~Zu5IZz zv16BtJ4r-hd=GI>9+H#mq1PSp=^YqA=14qJoj3l?oG~*5Q(=xC^VskX7C-AdVX+On znGsLbvB}|6O4gYj^Tu-0$GIQH)SYvI5#KrimNbdgJNhqaEki)Z6B+QZKWJCpX9)PY zgFLm2EZXRI_kP{Q;mVeVAa7i%Cg>U{M5u9(;x#fS$okrX$&%CERSZkLxR*{TL z8Tw^^DR@cB`Z|&-$<^()tFNNiVSZvu(V|?J7{MQE)a7rez$3D`Mn}Y&x=CS7HE4u$ z9qcJ>ucVg@TeUE^)IU2;u1d0Avkt&SftTVqW@{iTXP3OmmeiNn1w)1g1O+fl5+8RNZ6<~e$ANg;W5S`gWi;4O9 zlztXD$xr@WPUCs{f}fU?vRP-IP?>O>l^e-y4OO*r(}TXOAvsDXgY~fzyp1gAm-b(%sK6n} z@0;hj{LL?Rm48yeUrFzmbHfTQ>j^h0Ye6B-s?8DW7PGP$RD*#uQ2bvSEC+Vx0hgX| zX_9Y}%j!WaFXF1?_ydrAsMmz7slk^biJPMXakgKsT#t1Gf54?`m^K;y1+86Im@DQi z&Q1ctILAdxbZ$F}M2Y2>;g3=tvlf(^iPtN|?w&AUq6CyxnW8&TOQQ zOm{uj7T;e8*gCE5x;0z5bqv)yVHDLP!)?MaEj1qPd?#G0A+dZm%HRCheaWl`!@g*u zW)ADQT(D^3e3=5o4=(892ClFtYi#tC5_2RNs2*?$dFR+cGDdz*F#3V)VEpePSw}U3 zPf*mHP!p)&q6EUEn&>281F}=#9lyWqJy-QrzoDng8)J%!m<%31_OBi)t)l~nG3uZZ z!pPaub)vPBkk4q?ssWgMhrWn!JmE0#AUkhH?*=@Cp{z^>6u=TigGtl_p3QyAK08~* z^%`G3sLyToodj1FIZFPkcmkA;AJ$L2c{U6DGTzud7zS+^cT*4i7$wJ7pRa(LE{2qh zsSlkFku9uz|IWc^iiynp0?J1G^_7V|jOHLuq$NsK6mlYhS{+kx=I`X-g*<`7g zCaSl=VQoMWEH(=m& zAC@aGNmB^kBCevPy<-3M_S1iQk*5fm|8Q&0J2d={_?*^rbV9-qvca~Qrefj{LmhMx70)@Z29Irxyw1c1EB=yZ z&<;iX_34R4Uo=TQle1CBiqJB)Z7KAX0958Y9EaL|hD{M%6E8+MF=X_;Fd0uD24$J& zqI>4kDSIPPpEMV!TgK(1>+0@y2K`%w**>_`@JvOW=}%fU%6DO>TaLt3N)j z)3klxZt>nL>b1yh@Ef4(dV~+&`LE0vyyAHnUAzmq2>+Dv#%zfgtYK5BXy(B18%$h= zL+zfHW}Ij6t@}q>e?Nty#zIbjQpT~w%$Mti+?$`oeKK596T|DTf6E5V*iCSfN24;4 zjikK6KG`(Da(F+ zx7vE#aTB8^G{x7B1^u)GR0m}_%?2PA_9b3q|HUHcg_z@pT%EMcaoG>S01w=1gC_FD zFJV6KFm>mAvn(+qW%OVeutujZs0~}u9&`>JM$YdRGv+HR8LEdc;Hv(@PO@Qh=Q~wg zK)2d|AA4#8(B;<;Ox8DRMan(!=x6kwvM#=&2_a**qEDsWI={_7j+FwO)lF5{3|h7ry07PNQUtiethAXJjg66~4M)q$ zYZI(gXa*_{9Lm>q+BehRz>Z0AUYZ`!C}1Mdu#;&guP!Gdv8_2nl+&Db7yTkL+KuVV zHH37XR0@-zc5!}sM6!;}3O<}jG+T^HAhSziKIf!I_ji=2fEoj;p<|;b!hb=E?R+ZY zrVS1adFFe+|NTDjs2(9_aAgV`s$~YE2%e*zUMe(2{ERAO4qQnBQbGa2VML^A*iFF1v`9%;<%4vG22=`63n>A8pS7jF~d-8e`QI$w1P1FVc z<9DveP+p&0!eD45o;z;nvFxjYL*Z^N)ERjp4z`}Fr+<})@)p~AA^tw+Mqf7X3XLcwo% zKaCu|yV(5xQn0L$h;A8uD)T%6C{(hbAq=ApQ8FHlw8CpFLhb_B9idGsLaMEv?Pdn* z_vi1e#wmu`kLNol*5;hk{sSgvaBJOfmKeM_VRrMO@V7!~ZF#zZybh35R1ADXvw>hy zCvq+_>u^lWWPzK9MBK7NG9^E)fghO5B_P*|JrELgn~h;Z<+&vZlEE^9MH?Imui||F zN8Rx?PxCu=U5?SlYojp1EYANiK#&iVSJ}=;xB`CD6knsi;i^5-U?;d39C#fN>Wmsw z20@mO4pcXUXeIb?=PEkVuL-}3MG6AP3U(lTSzzTL2~bY;(~|vDeqa175%gNQQ=Ac4*w^j>?YM!JTP35r z$xxkRtOpzXMN%Zxa8D@rSM8mLpf4pA+Q%Do{qw3wp=ZpHoDc7{s#};gqnUoD711d0 z<+^mHfi0A z*~Kwk{|9nH7(i3`q-L|4jXvKOH+X>vE}>)2U&!7R-PHaF%8FJcntl$ zRx23s7DI1#$MO$Lny z3D7{28k77tGKp_+9=VA(5InB2h;He|Haa_6d^Z6H)Nk=coKMi-Oz{>LxSK_!wk@Re zlKr@0{fd{4uQUc^zKJD9k!6)NQ{?8MI9hE;ogKR>mpE=6fu74au*jH~t8i&o9}!r> zG~7rR4V#&MKBt&1m8gFlYY;nJu0PZLM*`ca;~TuM;wa(Jv@kRH7{u8!eD7K6`rjlU zUZN{vcvUiyui|TORZ*bhc+K?(ZI8x8_t1X=y>l3qxi8U^H4&$-&bdJc*hI99J1dt+ z`=O=Pg#mMSa67SS%9~rKzcDp}+QI7AZ&=fOOBu#ohlW44T3pRNWi>rujvq?7@bisp zlwEQ_Aw6hcFfyS;g#UIGUAfvf&IvXb?6WUcN;;rLEhN_umkI|T+G6^rZwFr?9%{QQ ze&j4UUYLvcBHQhKS$ms0gtoTy%4n7#mtwVX>$JRa4=9t}s{uDoE7A(Co!|8#_zvuN zVkW*PZe8ms=oO0t@bk6&2D;1UkCbrp7JLY_noQ#}i&!)<9ke_wd{f1y?m8A{EJoMf zy+PvSJod(j@6e$?GhLOZ8pE?Y&2Vq*VvQ1hiBM;doiJ;no>|WC2?j(d!O$hbzZbJs zY;9~%o01aq&|l_bre7N`Pru})5?yaPx)Agf_MN|is)ZmvRciVjJlP(Fe5+RR$~|7M z;Sn2)9NqfpW!JQgco;x__rJnt?+m|OzFkuo=d{suqLqs4p!x_a)ekH_Vm6~*Sp6d^ z*rR4KNL(Iled+St)vRyqU@`FMKOpq<1b4!-qzQ<*zF_UTWC;I%0YnB=fOH?Tsnf1c z%9LR-05GBAs}?%B9r^}Dk{>Ylj1f1a*^9-de~YjU8h|J#{ZOi zn*N6|^Sz3P{9<&}dXTRw!5Tv}M?0{S5lH1w=@5iTVEfg0Q>NJ06&))TL9ce91rtO( zG`agG59K!YgUwj_xIfsr>kQ+pIn+UAtW-hmwAoj9 zr*{>)i+uulC4{6#Vgjk`&&y1J6UYTT0#a6b`$E2j7{u1J;>oJTJqN=q;1>_eXGk;4r&P zb$%ra)O8r~8lB2?ZKo1NH>UttfNoIL@N% zIu4w?3Y}_{SHsRDr$zqBF@dfLkV%3`Q2&n9$J!8xM)k&eaDWRSWYTRIcv$s5ack3} zR~!BC5!dltH8+99wJM;*Fq_U|Y^UL$7l7?6ix&}sBFx%mc1{BbI01@ng73;_Ke0NK z{u`fuLolsq^?g^e?57Cm_RCNLXOYAI-{@_P+s~{6n#w@q%ko@5X&YF!sC$6MW<~)K>2XO*X`~ENn1j zs!}HrN`q_Y&%Ba#ew*nu!blPnIc)~L>aMXjd7vh^Re!qgq>%q6q7NTIUCm8tVdz93 z@ddqaq>_3)ex$T0{l41nY!YMY$?a`dt@;%pMMj5&Pz5RS76jq}b?2E5X%NFRR71k+ zXRE$SEb=R6fj17N_eHc$k#tVTse4r}VM4|GZh#XQ3h#m(xnIy3d<=Tg7Y;W1Xe=bq z4rg`y<+}!OJMYU zIDl7b?l8mpz;Ua}zo05#rA<@5lj-lb7_m1Zzo0WnleY4Dl>43JMR>YZ2FH6R%h6!V z90w%K%Icubkva%`?dqB`$|(~KNh|a#8G>Ag2Aa__BptRU1hTV z(&IL?Y@w?Ke<%BA@_vQ1F+agQxnw);bkY;3^OLzRX+=|9Y5t z#Wn;aT!Qg;{lK}HeIGgd_~%>{fOF~ny7vnDj=4TY5ua6i$haMs*8xh>5OQB;idxMB z${_l|riqXrcl0pk=i^&8B_3u)>I10zc4vR^mS{VX^U*BgD;+T|ic z=+TX^PKy809e5b$8Ri@Di^{G~<3P)q$`m-5NAv-$-(NBTR>?(o7~S*c5nIZSoCY63 z@qDB)A9f~<{(U!GU5YW4(Z(aF+w8IJl(H_D&ZeSK&Vq|J+o${rOVf2=?gXl3c&*e8zB z0<;?*;x(!L?{PEeX8GMz8>RU>L)hr_Z@V@?8uQ-v`|mOLY!R5wyEZYUeMqi-lp9gA%iP=@G#(Qf5`HW=H0tiM(p; zR0w3tW`y{gDX*=Lmtz`|x+O&xo`n_jr`S!DeFYKZ78F8z^z)|}q zxBb&wdP)godLJ>_@_uOda>&7&6pXxdb2ON4Zz%G!!EYSrp**G7w*hx5GegbsW*@v= zj9bDCD9^Qc2?P3Ma?3GFgb|W`ZzVZ#&vk9J|;m|4<35_Pzq~a0EYPXEqZ=?ri zgnp-gH4hLjg`@3qAbtYC)@lH@CJAiJSoMap^7?IVI?Oxur6-DQC(J&o?K23>AHd(Q z3%ZK79I_sDlnH2+mVk^dvf^$O}LctZKr)wF1AB;_0dzk@1-NE zMD39<3m!bcl&qy#7)81kGf$D{JowsbjByJghP2gR=p@5MW7Tp$>ax=&skHKbM}rB4 zb}gtZI%V@J>JM<{V%W$t)l0w~(=N_R;4_CDJBd8GQtlMOXPAX(UBEMH;#`h;IRzM7 zA&);sqg^JL^VHE3lUSq-LSf#cYmsqfasz6KhWfdnXE>x4*!_~!tS}Oq(iB`lQAF5! zjo_PZr+%f}#qcfgnQQb&^;?Qx(j-(2&2k-+vssZms^K%fjAK25XKo~d#ZXq)2wW|B)$W@*xz%@97Dzr$9K4QFrEwj+YLJqHsFTTrC&~NMYH|EFZF8KdS%7obC^kSr4qxTy$qo^RT zl7;<2zim;1jT*u+(3rn<8flvg9vt+nwpWBdJ{*u;eF_5YA*1s!(K_fW({?8ogh8)ssT|71O z;av9e`92-p^`G}3U9ZLX)yAb+0?)fF6|lLsK4ZKIgGduD3s!^W zw9pqs`{sigYt6b(bteQ5Z#vnS9DLymxZy~C&;gDfVu9;Fpm)j$6~^w*O(pPloyA9D z;TzAFHi68l12bE(0tDK33sRK2SXz)TQJH9&l6^{jBD-NdZsTFQ(>P7A%0Yv$hg zyQ^wkx8t^CO0yS5h{Ql+_1cAH-xQknQm6!*T7LGeX&H0Uk_2`>$e~( zZN4Q=9mSkCEI705K`2NnjB$oHkBRYS${6-A>j(`{W5LoVWx znIwz}d>uR#*y?ylRrb;fgChPsFre73DC$7M3D_;VzoY+YjUF;UD+^w;?_!ABIjna( z{kjKN#uE2Z$@cW7Gtb)%^fye&I9|Q+`e>@ig`M&}?}3J4Pc#u_1<(D+4u4NO!GalJ z3Dw>mO;nRg?jZV)Lr45jkncOqlEb#47m+>rN=uzQA1BH5nV@wjO*Lg?y0?0=f4#2) zn{~3B#sA?W%6|v~2?4JEH)h|%jYy=}nQJPgal!qcE!LOC<>1Qjk+p41oiWg0z!WGGrv;T&*`xX)J+F$elGnJGl(4?XR zIZe!8kV!gq6$KsT=7rqU8bLB{8u%wc{Nbi6!p)Pqyxj-+0niuDT(nk$THpwd~5KH`b9xUM3o zgd6=^UqKYiBq>}z9G!SIY@HaoaLC<;3S^$mG*+ocQ|7=ILZOi)fg4Dm_;DKg{V`$Z z3Pa+@$9~gx^i{JypXi5t^nR&7vU%t1{Ihg{pX5V5;VxihNPT3SX(Qkmw&c9tuZA+y zo9?Nccb4=SnKUKZi06Uso*TbVzPVz_9W9bsw-q_M$vDZg9fcG-uaslan+dK~oZvd# zeIqddmzs;ZWB;c~(RsylJ0@Qhlb}31&#pp>a+F|%UnMs+U0vk7nQP}vH80r59&AGvE5oqjQ^SwG5;XV(2HjRnKF`}{R=aB8Zd-f zfn1q?+fz%CwKZV}66|sQv+Jt}s~V_pufU=XNGgI|%jnQ421w!7RYu1(Hm}HD%>sJx zL@(yleq^N6MFj4e^{EuI$XLnnvXp0aecqM5BKGopCuUT(&mU_L0x;HHKCFe%-4MM` zM$|-N_7P*JiYbFuq#sz&k)c2+=puHLfx;$eJvTc^IbYPecq%$TWq4q+D@(Ah$UNVD z-i@?ti9!7ui*T0nr}UzbIob|C$co-y>R|HQ%axjPMLo9goe;0}%Yv4*DKSG(a|gr- zWY+ShK|^oyB95Cz&GHzoKOTqVQ0ET4caFw;?oaKG{TTU}cVx-&m)ZeRRy?R{!Ry6N zVx|*@NFY;HuPm+iiznGd0IT(XHSK!aH=x&!$N7t`2m9 zVU$!n3uEOmo68^gy=6r|H|gB%>;nF!O7Qe6roSNw0K=fMv~coPOLpgM(8hFhVG=OZ zAEH|ECiJPVYw8<&12+(BEFz={_P)mpxK zH`X#>)I&{~zm=eB-r-Ew-=zKeT#}5+B((bn^o6P7TdZeNX2``-0Y_W5ZMD|-k@%?} z9$z7(4hF42c;biFjSV9TMu*Fw98zR?SK;4h&q@~^6(~}!X#{3T9L9%t*Dlmwj!Y%0 zo^|#Q;RAL?Ulh!-2+%Q5%zi}Uf3hN;sz^Hp=16vz!)${+p{#~Ukf$CP<_=VM8&{RDVGhXD_$UD^gDX#s@DlDvh&9BRl|ZmkO3KS%!6a>9z!xSA`c9%VC>jD{y2~=V}OA@Y)7~p zNiB!>_jr*+@ujfs#VVu~Xf(l!_Hr`ctw582Ic1O|lK_(D%xmag{<)}L$z^^hlh+W1 z`wAo~BHuO~(U7XS2oiQzww!sxKHJ~$C|Xm3Uf^8**WV2RlLrGIuXyoee?Z-M3jo5E zLi|wj8w9B+T7s zcB82y2*fxf>zM5no`?R)P^xCJzBmRpurw^# z-bwK^PL7vw9GM00JaC@-m4xp}Tgjna7!HU>75vR*1qrpF0-SOGpwkrsk-pnvW#!F{ zk1bZ;GByT@^%>p8XE=IkY9dcKy1Bx3OZIKO5E>|_f;RSY%k08$>V9~Z)|VOi=F|_i z9+bJ`^4$-(tM7Ufh?cRI&7^hg5qlmB(i#ksl!E*<+#0ZY4$NK#E_5(R8pGLmOJzI4 zw)mSYuMDn2;mGzv1mmD-g`fz&z-0{jSHX)zUpYZM9uKcRZIRQ>7xjZ2^Z7}A>R{+N ze0%+qmxRGbQ$9JlH)UDzSqw$eA2NfG&vj=40y5yfEvgNWFp<7LKlrn$dW5ZtPuEG6 z;72wS)kH}|Rv)n-z5`&E2}vsqOT@V!!zla4h!8%Q1_H3(b@iv(&_PGGLlP{uej0%< zta+6i{5#;yHXQvUH~zTmj8tq8jJbG2)C={1+>*zcitJbjnLP1_(oBN;ZRZfnhBn3h z>9e`OtsnkNX-@iEnlly2{4ZN=3i_h^YhMHq&v`j5!`o1pFb0l-1 z2|0!;NOvjF1Bo?JFzNcLJQyh65RREttI&g#$^_D*9yC`%%ajdoG4NGVOcTOleQ$!; zzuC2OD;SGNHU7=89U4FwiIsARKHyvYUfcV=&F4D;5GK!E6UjdHGnSLz*@5{1H?Dvv zi^emLjGbEOXgdF7p2h6j^Jbss>-Z%00tGsmJ`x!^8T~T64vru#o4^+)Wp$C?Pd7CQ z)bs`neDJlQm4!1sy|pls)JhkeN{ZZSu=QKIV6di-#cspf7=XPIEuRu)qTbCeCugKj zI5Tdzj}8sqb)mxn`8kT}0laYpx+ZtDJj-lfM@;x_yZ6NdruQ8@vZ6U{a-Dc*EDmT- zWYzwtmkL^Ws}1S=Ly#Uz(G!_8TQaG-s082Y#QBG60>Qo4#;D5C7;F+!3xR`(`ZwFI zT#!XAkGjDrGoo-5-^g1%et3CqeJbOF%UoueVV^ybF}fhiQ$gKo;;YOf^-_So5M0xesRBYT_*sO#mjWd3_cCV}3UH@XkWXPOyM(7n`2nQ>pwKW;QJ zj9v-m3A|TvLCi$^ynm&|NvM(Rpq@~M@XkvP9Rg^-p2efbIIYO-cl$9-_l@^ zIA=^D!As+PNp05rObH78P;rQ)ol^haSY+>5&)DMEb>O5XUM{egaUlmDuIse zvf(>91x-A>X%hQ?={~E_Dk|V5yMmvDfP$dU_uIq;O`JP;+ z{$yOgR3!0K7>3s`z4|UpJO?1pZkCOt0C+bu0WaaP)Lul;Hwke8^ZV}s?Gfq8ZRFm7 zcN7hn*_JRZEY0^PCE(8EA{^xf!|Jks9Wli6QYjg89j3R75oRmT4`W;rs=>WHw;pA9 zFFL5n-khK;&q=eX60l}@V!k=j!-tmnxX^OF=zSm=$9T`GRJwjR#{;fJ${UTWx1_Z!e`Y!`!2 za2?jIo{WrbtSJi4_6r$AqaV21a+=H^hlM~Y5Wi4AX|n!=p2Ey`A49tJUK(TsgTb$Y z=;pmB3P2Da`zNYd%B?wLU8LfaWOy^x%8rXz<@dUba1^uiKZ zv~&57e~k|voW%GGJ$0ktxT>glg$Uyn$(pir<-)cy!eQqmz_q7man$%z$48T#a5&!~ zqPlO@H9M9k9~v|(CVazKrn5CWsu*G>o4Q|-<}Nj@NF=g1r8G&H!4w>Ffxha#ooM>X zs@kfVFIHo60(GZXs%MHZwLg;CI}RAXGz*?oP!pN-`DpUau=WD;M*+gLpm!Yla;e4F zjD9U$%z-12H) mIjUq_YLq{UxX6Cm#MB-J#3@;>j03%&ofoTdd8&590Y^Q8U-hMi&C&t?EYn zmHSQ{shR{B#%a$gq$)KuCevIDHK%p}{;mCT)&%OTtKW;QaVT7YB;AUbuQCU?oe0V% zbrfVWMHc;I`-3r<3(~vELO1QnlH~H`E@9sZ-zW#+Y{qSoPjQ{=j33FKpO3MAJMWnq zio(3~F*x)pnY5c#r7z^8=FREOa98347l*gko{faSrH`ZlI?{Lh@B|$ z*72I3y5;>z+dllh{%Qlfw|K;S4ZQjYygaPbc*y;}jyz#@v9Fi~?O>T*p~lo5$<5BN z+|wj;HHyyF*xODnt6SZ)RSET-VJl8D^t&ecI@cDJcvtbC$@Iy;W)ObASx-m7oPc+k zfpoR0WUJ8L&gSTS$W4Hcavcra#4e~(-;4T%DOEV7Xb~?%p72g`7{AwOs#*IUa#F*W z7MH@Zb?f?_lQ@n(5_)LeN!)h(VjrB&m* z7CP{AlWO^**(e=1F>HOeVguN3KpyJ5m->)w;05_Up+%vu{^|eHw2FPW( z!yNkOk*^K*38Gq1;6(+?Gdc!l*{^SCIn0Z7q_ivZC~0Db(8!(b-uj9NYyZ3eVSD+} zw5zQAFK>UiHJUxVc(L_UKr8$6sy*J zpdo5{f6puP#EUw(iANTP3rKj={hUM@2-;?u6#Jc$E(VSnhI7Jg4_>=H4);0VkPIk+ z6z!ELb4H54o*>NK80BlIVM#Oj9%5VoxMW+A1&DyJei9*b*lx|yNrGpIkRcITG94dr z3aRetRA4KQ#XsPD1I3@xnWw_DMQ$xyl_j9MMQmN71jF~`itN#WVU?0^br1ng!2AG4 z%9cZD`1cYwI?oJF${Ju4>Y2_Jp=-)Iqn3)ngu0LOI?S5fF@y&K79_tZ3ADz$d@x%f z$nsuQy|X`JiL>x|a~%|i2Ujqv^Rqg$C6kpjixKD%S1bna--gi*45?Wz==bv~ouMfg zr28hDE+^W`bI&j3fv#R7t{^@iuw0VlUiSifeVP8p*H-Rdb_i@Z4-}|i(GthMX1?Qc zAA(DLCg#t61?-sM70<=#!<L0KN1#d;cVW zgCG=eW=aDZN}R1vjgpx!vwKt!dvvLzas3{6bs37}wF3JpNq~n7C|~cr#Wt5dUl_CN*rb zQ`Q6sNSkn{N&qVEDv~+e9+HNk?>F$cFYT%U@vmh%SaShAN#tfDVY-kcJhco{x)VS} z>~-FBco*lcj!?vPTnY`kpUmppPQiFZsF`>hUAU}%0UkPSr9i2e47BleK>IX$o8q>0 zDtB<&1jqm=ZDyjz%y*TB~ zY1jLf;~u5UR#K05fJNV8+y_Wdd{-FyT*qU>ad0@DlQUd?I||pV`^xVPv{`AGcUu zokE%Uh?aW z>i)S6yjv+EG9%GQbQc*j*cl5!fBK_<jxX}r>Yy{np2{Of+Ikaa$0{VSUnus4%0toycam)yycl~fE5pL zKPaha4Wlwa_3*=D!$6?3s#1oa6&)&1et#gGzsP+2d0qGj26MCgkA6su(XTJ$;H>rh z9sY1{^Ru8~(oMjPY0IXqtMNlmBcrg=_M$e5taqR2|gAxQ8(v2WnR|YsCl46;a0%s!vR)Jbo7XL zfgV7#6)8RT=B^Rn7v5hVhE=1<6x8yb+&KfbfuTU=F&s!}tSZ42K?I0wpMlHv%dNNb zY8$lY*Ez3&APOaF8z6{-5Pq@LXicu#j9$`jRqVfxkb));mO1xz%v9ly7qFM-9MmHi z)Q&NrJX~&Gr2h%A*nd)Xj|?G7^7Sr}ZCTt;pGDPrrKw*Kc;{#Q+#v9yrS<(D|TNeH(YobiXi0aaL zfwOxdl}E;xl9OStH_@VCWsKom2(iv{O=nDGkjy=At?9G2nAyxFwK>DSBbeWJMsTGL z&Oc9x0a^Pk#i5VK?{4}-t-0w?%qyRy(nFIExS}4c6ueDJ0Ux+zB4XDt>4LHrJ+*Wk ze@HY%xAEm=zl}*h|5&6HwXagED57FOmLau2;G}8W%*8nwnZuj6(Fmbo{9IqrD=Tx} zPK(5!J$hC@Neu0;Rh)Xb znJKnH#7=qIk~o__$K)`+{8w&6(yG*2O%75*zpyqJ#}Jl2D~a_RDh%QJ7|WI9H`nggbqXV4VJxGEpP|F3-U#{Z2^~cr$neru#x-5`-R3d< zh*P1D7th@861*i?%z^#pS3(%A43hb5fl7N zW(^9ZU3wc(o9zii1_M0#9Rd4L7nUgHzD31k`E(+BP-zqYWv^bCPAV{}y|DnMyfR0S zv75#pjGS=|)>HMyrid=o#fpsH)hTDe!00Zp#den#6>8Qis5%3u6iT`uZ#Uv`SXkSe zq;Aha)-KyRDX^l)8xPz)-Wj=(X~$TQgpu1mI0J)8Y=rC6f?~zd-3tL4?0M*MiI@t8 z;%XOe#LYz;eqw%HEhlrLBi}x^P6r${yZE29 zd3D`OG0Z|+i9vX!w*O=+2FOSiSW5bQ{zq^V1k`?}gaq`34D$Y)Q%engJSAmI??UMD z;F|S7$GwDgt%j>m_HgxL{l#ajdEDhF!1x`)(kSH|o`^}1Sm9hxFNZED_@u|fG(On86|0=^h;~#a-Rq)h_@;;GhabE* zIe%lV(2zYx;>B&ud*Dd8hqCqMjpK;tvaI(9xj@Fk4VqriQIn7~D@i|am(R>jE!v$I zt-e7@8MXK+G!^>t&*eV8BZ_+H>}_NJ8+AP&j&S2SHH=e9yz-Wn0Cj?^`g7K&vwh_Z zQLO*7Bgn&rf~~Y8{uQD8)boUB$*b2d!BQcix1k~gM(Q8gU50RDBu37E2xS5#njV&{ zoD5NYB#B3p^=(aio9G_5Cf@YD=qONXiy2x@JLS58$4Pf>^mG&SZO|M#vLAqd2k&W> z%?Nz&<%gjSyk4S1xOK5|aN<7~?nMF3&QXmQRqc=br*mCwkZKoLcE%~><3n{z8#6s* z`OKf%sSYLzedav1{HJ|;9-INJieM7rIU$&>_c_PIZreUmFrXy%)58(D_Otwe+9@Ss zDA^o)QDUSaAA@9sES_DeO>k@Zt0#tzPe`OrXZSmV(N};Fm zj&7HdO~krziRT5u)0@HLCg@a)2ixs38eZeU$&}~PhairjGdWVM=ig@`6|F<-hzI{^ zX1pZ0`MBl(9`l0d4Ogp)+#_iFz~4g!*I{xd-v}G%nT`#&QRHSv%UP*EnM!tb|Oc(%A!&YEHr&9%NJ#4@bzj4 zKRD*mf)3GdO6tvPOK@YcYkY)_mNSp;3{Fm3BGucG1k3w^iFKMvkrUpNAz^dPNXmd5 zN)zrk?;Jd}?E{bp+#CVlBq_}Ivrc~w)0*prp`2BZfwwK`ohbgjBJpo^iupj9P~J3+ z9Mtde6LV2GTuXmdor!Z7r}9gQzr@tmqF?Ry25*MC9mC9~AaUD9J-L=mNT<-!$x8YEO={3DW|+6I|S{Z|WkewJf2Sl@w#r!z*hhNRj71g%W} zwPz6VT@SIc$XQFn#ic?xiyh|C2WCLMJaS)5kPmj=8orWnC)}moe=Lug+cl=hXf-*K z8@&WFZIfbQkDup1B9-9*ohYbk;=&=kl}I=es+B?|82B`eGU&G-mGYq!`-W{}SeiuM z_Rd5(oj!!05Kw=Kbd@$7BApwHqcoe&ghcO5738Ps|+`9zNHufkO-}db@PEnfieme0m zAl=-l)-b^kG2+Ihbo_22w?B4jYcE)~GpN%WRG~JgJHcK_eae3mxWQT(f;u=LinV&^ z+}C2bW)qn`GgF@vqw`JOQ=%1tnU+Ech}k22VDo{Q^vpi-@a1(|CNVx1@?0-bzZ=+% z8PKGF`)^1VaH05rLQ=4TCT2?ZJ%r(l3VcB2ua)(_R!6ob-KdBYl*F_U-vlwynB-lC z!!SG8SzGCs{f|xlC{EWqXi>!7A|G4=L|I$vla8#>wQ^A&16m7u&AUO6{d{`@KzKha z0kg8X4fl;y^gjVX!cwgOH&$16`}fuWDTGI}KQihuABh0kQU(v_xH}0jV~Q0VYjZyi znm8au04lXVH}2vCy2$Fm6-S=Ja%O6i8}aT*-~{bu%4)0Cvvsc3R$KH~_01jgY?j2i zJk;0y6P5QqJmv2Ss9-b^bSe!f!@-)D_$V;@zzK{YzigWqjZ%-tdA00L#+Rm4Y#FZ2 zvOTs3wc7?m;5BIng1+}sMnS;lX*Xae6s!f-D1I_>A!Mf^pLq)C1GB=cV=|cpub^&`vmtaz* zfr^u(R;JKnuZ4X;@Ru?#P;|1;=?t=@HglJ@=#7QCkF5N^NAR2we$?#;+2q_7CZx^S z97C=t;U6r${%oi5GFaqZxz_drb;xshzDjJ$y!t)Bl8O7;c)#n4h_T_;1zfm+mf%vP zd%!cs9QcUgpHS<+!AM1$MBtgj6Ut4mddZ!5o-Fi zlL}L~>xNW5WQp*3YeZ@|=oIA;Nd*m(qg$HKqS%(__Wx8HB>s}R89)(*A|TiE6uk9f zuA?#|w$cdp-t16-L;j*|KZPB#5OJ^Sx0|ia=oQW459rqut%n2sDct?bK74MdYWbp|_xBx0ECW8aP7b`KRk|V;w97e8E$~7B(M(9tp??{QbwSn(skLTf zIz?^H55%?#nekkZauAKd^p-aA8Fut01K$=#_QKv{{aq-&C=ut+m;gJYoV?Ia?2P3S ztzA8`Z#U<1m(`{y#d`!C1Sx5!J-{o)Jr64fB~mMST#kKBoJPu2syZvVr!qEz zTzikGm5p|qEZ``=H<>154Iucj=taNk15vMjHDwkiz&KS|2J{4b7ov$>LxURwclj+) zZZ64nP1FZ(@_f_=EJ8L<1F78iQ;0)EtKzA`B(78CcRIG(~IdcM&~2CODc;a~v} zg-``mMLK?+prd~X+m@4mF1SYOfjC)nF>7NFn3NGM{5b`)^LJ>1e!WfE4_YD7kKADC zuEzJQ@5K8s!F(L%EkX2QbhT9K;q)`!R(w>_U~D4`-Q<V} zjKOcBlh{OE#!MRJY)RrVGw?9zW5+k|h{;866DKl?2t^VVYFumsNW3qWa;8~C+-Yg5 zs467Dara+Ax8=ylOUUH3&^4^g3F$`>&qXTRrH>7L`u|4Y;6=w@AHGbVG=WV62OxL9 zehK&{y9K(@b?95XG8!%}UL#MmXgTp!zw-W-0^4iur*Yhs=zm4+?)&I3l@A3 zDCB)A2dFmSAY%2M--YFFpW$zc+ReV=QC>K;1!@=lXIeP8$sEXF?*{p9Xebov*fJp1%gmS4eGWL)r`FGFrqs#rcIuqqxXWy1M;Vjgq! zm%)M-$qr zi5k#^-XAOUJu#B{4Acsa1b00QpD{c2^$OeW7yk8O1x?~37U(X1;er~}UokiIuXR)j!m(c1qBEyGt-dh=>i#a)tUf0lz9b0)7mnH>LJ-&C zTK;L>9rI*8C!uub4=q{v%E7`NG6^jddX6ekhqz(E%g_DPyp{IQ>WTEB zSn?WKi85Q3HlzDuQL}C=z1v}FI9!IEqyRHC%XM&*y79N&lvhQQBD7AHmL*>aX@54I za)NgBv9K*M!&f~UH1k%*Hfx5gY2^^Aro*eZocV&~|JQ|7vwMpBJWjOcc!fYG*Ds=9 zx!Yd>Z2Ae6nqgJs2XOO6l-#Nb_mtMddi~G(dt0_2OAhWta}j5)Vk8|JG(?mG~k= zEZ3`^_)|j{o&g_W?2sZ;!gqf)%t)sY-Q)uYD_lU5)t)UeB=AHq~LKVHIe+oGePsMDTUZnJf*pUs{A%g zFa!CYMHIA~f|;;P6o#83)gQ+hb3X;)15jcYr0Iy)yq%jg`k!g8@wT@x*3U7Ws$#Zy0L%1G)1Um)og_lC* z^PG8AoTRyIr(O$pR#YW4%Z`)Kbh`^e7Spls75eRmVnC*hwPmz<)!CWZP zs4Ow^!lPd={2q7|tyE7Bo=3y1A5ITQsUUROXYOd;H^1+FrC{!UCdc1!oqh2t6?sB2 zZ#k|B+E1**aJ+KtmZEnRY2&4xwnS7}&NM;abm(%K4_7?h@|F8=QLlxry2F28?138e z5@^BCZ^$8=y^SQxclYV6K9set0cmq}(UVkIQ|&T}C5$6{eEw(4O}dc&(Ze*B$Xv-g z*5%d)N<}W=r)H)^JjRgsgc@Ql&z!KU@6dI{{xYJ50tw|OE{j0(8!aC{Y@@P+TK^)| zbgbS+L96TYkoPdw1^l}lUrYC@DRRn@iTjfA)oGH~{GjvJ=kn3lEGS(x_)aGTc z?vl0w^*#Z$3T&tDQJ-aFHstv93ymX7PfJb@oQc-^3;%En71N5hV-QTnOF9gm^RYjZ6A}^ zWZ(5Khr2XlpY}Fm&5rbf$=1}?iw6EZS<{ob3$})(aQ8Qr$HwH`GKGUarl| zce*Q3(EU)Fl|3zAtnY%2aM|>qmWvp?u%paI>b>537JiWe*<_h_FQyI;rZkpa%a0$- z#Vk-+7&^6V%XWr&vp2Sgw>?bIz6k;2yJi3q15D`)cR`nEhQr&1lJa;_C=p^?Nz-o| zOOhF+v^0tzfuO8Q4>j7b;|uRM-LF>{GS~1r!k=;a59D2D%Na{9b>^=?Sf5bv?zHqC zZ2EjA!E%-us@B?178EghVJBI>1Hzi4I^CKO{<@*o|Ew=5PC_1q+7^o<=Jtn)#nm%} ztL4W5#ombmnP*|9Jp<t674!U^2$a|&?Xjhy6*1w8 zNYFl|cbQZvepktG98P!Cuc9!^T3}1vq9TrZHVPc|Ue_)5nqGjyNGdcaXC_V1-~j+S zBN{cqDQr|`xTf9h(xUBwdk64_`7IU4RA;xaEkTSuuS}a;A>Z*LYY02&w%c5^8~>es z);3il;O*!A8=$4?m(I0K$KyZo$PfeI@mLqE^;Zr_M`*d0kj~fDo}}lUCsG*%qFZ=* zl*I$hT@ftt*c$Oy1pk!zNfy<~m$w!^ZRQfCdzpO0mz$~+u?k{qF)G?N(R}5^yMIY` zPEh`oqAu+H;A76Id+(#$+ZrbRyGgiNgxKR;ZNb0zY>ryXyg~2tyIIt)rMH<_JGG<; zy{F9d`YpFO4afXh4KCo8C>FsmiONgrp_|pwI0(w1F7@%~GODlP`W1>BUTMoNvSi3D zsDVoe+L%QpFCOp00U<`ul|(c09HV2GmF9<~)(kq7ag2}wjF@I6YEGIG)Bn!}VB5tM zZ|{)OJ4sn$)S9Bou%t8C)`g=~uk_e*u>9V_Z~;+SsnDI9nd5mlPn=^z3Io)wtdu1$ zW%=@jMaAQNuptyb?x|&m26;+>G$;M!_w=gKL=atZSKDeP)KNhykyN0XnbSy<+Y#`yLA_ru zgw!I5`NLMs5|4m9|GmpmcjzyB4})&|*1WIk11*^}hy09l1-W>bdwcXJ+S@@7q@i~; zbh{prWbF0k>q3t{aWY)I9rOUyRU(2d5x=2u6W-Nq9&jHoPnK4JT}Dt>n(~5DXuw&J z*nV%^JlMQHs^BonkAdTb`Vb2f@2u?{h(4AdqX`Z`0K?`#UatM_hDP|YeuLRC3* zWR05cyQ;NvZ0-H2Tp{x3BeU%`QYc0b|5o0w|wH(0TqxA(t%c=f#8TwdnH@}=t< z(IPVYZyjAr>nxdc19YR!*YGf0?^(l}?=RqsEyosHp_y~p_5<^2zCNZIbeBwYEYtM0 z&qz$;5me!ob-V6+!0tC_?SISVuwnzgT@MeW`gI+pfp}U#DmDvFR>!Eo^kr!XNjtxVWa2 zWvd*v0{HArCPe+iC>f?H|(H zR-~cPbL+Ed5v8zr9~!1>$2rGF>FVX3?_^)wP12q^cHT&yeTK|UJLRqm{eJ}kD7 zaV)jx2e{awzi{93%6@*(9K(7LzJu-LNd?4)q!J;!Q4I6Rwqr!Kh^1_{Gp>>nXWut5 zvSU8UpR)Tmw~POZbpw9y&O!&nb{dZlQf$Es8fJt8%{7lqk`|!K2cWn6`i0ea*NLA> zGB4s&S6*6gY2JM|mwi72N*V2ZS`5Mv);n_B>1+dnb&Xe>m=4j24djO#~sB-@)1pCt$3}TAMA6y!X`|9(4j*a_rJsZPek{8quf6stngYwqt``3L*Gh})*2wO*0Tq?ntW((>7o+`B zxA^Fhiha$r3Gd_)HePB)ABF$siw4$7)E*%9kJ|z^zXBwjG%PVcj6Az#rMscbB%qdc z!flBt#_y70JAb{cVjG}9{7y$COoX+x?_1GqHi`REM7!hl&V2GgrQ?sDIQIvCB=_Wc z7;(m>$J=}1vbeB~=Az|q8ektB4?cSxZ#S%{wL5mcK4P|zkIX7fo`d+e=1N8>B3=hv zMpnN$Xf6yGzj}%fR2&c{RL4b-xagQJR;NR>hT=w<;xP8Y(hul|Hpf4&Li{*}q=17M zcs2X@{rP|ptV_8={^*;&HHIQbreY{Q0qtbnbmS|a7S8;^dvD{u*1oc0y8gM&oIR{F z;9w`gPnW#;)Q<)u!qpquaDKnv2)kD6|2b$>yy)Hd85kJiq-Ca@qr;y!w(%P-2pF8ib%tv<(t{!psJA{tPutklB{im-ODF3#kN_d!F)qcS16 zgAio;388J$dy%Kj0@-UIbVTEu(r9%sFgGzwxbJ(QAjaq6=OUk=EmMYg(yqKmWBq$!f~6zmxx<4?T4 zOrKTd2LaSEnADMN*KGkEMiCto*uG+dI+ksK^g+m8O^mIuK6vD}-%_b@UVVXr#&9Cz zQCAMplHMFtQrOqn-QAsJ5c#+2HFzUrheD5xU(yN%9%UDDFR{f#u5G)OEYG{K$3C8% zgWzxEQnne}y$~s@X6dLHhJ-J-ZhUCi1DUk|pm{X%}eYb5>mcu_9h^Aljoh1IXQt-_{|FX)l?cdV~PmoPSgRz7~9mUVbFb zA*zF=zw+!xtOMk7vD4pKQUZu&S{>}yX_v33lV%sl-2CrNwbMR3BlU9yiXgRaSQUgg zYy)=j{<+?dI^E)p>!k>oj0TJ8K9pQQC!qS_eXadggT%%x`V{|V(g6Yw;wLS_F0lM~ z9X1dZ1N<*1gd7?>M*6QzeW46(QF$c!Rj?(X8=q-NFE_+V67Tanbp!REt;jx7_eY84 z`@grd3mZRdt1d`glvk(caTS2>^>Wb6kI@xgvv~IFP^Wg^(^HnW1$r!w1DWcF;uuI8 z!DLl*yKe0;cmty!cmmYP7Fd^vB5+HL>{p7i=xFPWyrY zE^Q$(mp#{MoWf#=o^z!X#(I)764DzI%uObvbiZ?mgVxqr zXO~Mf4g~b(r;Hb(p^ORnjr%CZ_x$#wP)PCOb181wDMm+upvUWf1)d`+Fbuo5Eo6~T zvT7Ki^OA41=%&|#32jW0jh(jhUG?By!-kVu&a@c%5d>|FNsF=+t3Z$(iNd71fz<$Mui_h4 zIzSu2ESjcZxtd-Kc#F?A_YZ`SL98_ku7=R5hO~FlfT`yZi4N;IE@6iFL?+&OA0?sW zAnAbfr5fUgd1u3Rh8@Ks6kU|q@j2>3#P>vDomN_xX`r5|gWG@RN9$FTdK0rBplnor zt!Vc%3=LuV?f5F84C;&H3GZnb>z}zG-MKCH7GdJvpDgDUw4~3n^54&~bx~e{V%N>P z$xslR}NNEXh7}! zT%8qAl4NLHV|N0?Ln|$D&GWz~ag`wpQ}eI{!tfY`0gb%p4&Sw~0Kz<+?Bg#4EC{?Q z)DJ#Pk?*P(XbH^&LYh}Wa?j9Wm?GAVvdeDC@&fHPau7_-8@KUXwtw*aw7nrypZ>2h zX|$Oj+Ew@l&CG<}E-bCzD}ns<-XmXbXyEtby8o;8FXePTE0teJ()Damg(>Kvk8h^R z7z~Dad$0xE(Dp9$Q&>oQVHNX3hegYxUN1b+MHX;|3@KbJo zBBpRsvvII~zqzBxYkS``<3%9$_*>eBK4$&H&C}H0nnL_k2eTFf!0CB|;ti4O%DJZOu zEcsU01j$CQEz=+W%LBkci5~eETlT6d<~bPjG>2PTFs_~`7J<67!B`y=wquRoz3JT@ zdGg*yp4IRx=33O+e}9sy+G_@{);8c|0bhB7p7lf5LF$<|?BG`^>WN~X?BeQe1!$-z zv_=d;gbvs)+o!ntz+2#Sm7nn#L9%ASW+O{bQ6z5qM39h7aD#F6ZN96R@8|Uz^|`+F zR+gA9rFe|=alUAm%&uF6tmil0!?8Q}?erhn9%^==0^I@3Yg9HJ|9BwQrI&lZqOeZ1 zq1vM71$9E_2;g~6lA>On8=~7pP@+ytX<>u%)Yq-hnJmgH-(2qAMJdPW_IA}f;9n1% z4jwQ=SW&-M30cFa#ZmR(pX#T+V}Cy<9QYIqIuM>_NMOBxUVadA ztt$5=uH`>tbkjPyG-fqGb~k}xF+6X%we?L$Q0CzcLoiv4&9LaY40Lb`JsH8{GKMZH zU_FztC<2a%_TS01fJ!nk#;@RFC7QS1%R8Hdl59qeb+sjfUlDD2XSuvmMaJz=+W!V2 zvX14Qc_Mr`t5IX>pAQ6f43C!SX0tLjxGg774y`9N2?zB1_Cu;W=I{up@&0+P59W^M z@R(`#z172Bvw7{Jo3_C2L2prAn@yr;!V?;JZ_}xpL|gnwkh8!TkRT$4`p%qOxQvk1 zIO#e#Vx}0lnahU%AsN$Wpb~JsY}|`^p&-|`}P9{$1^qK zfzkk1!Or`GuWs&`DW5!DA6-+Q!h>1GVdOCmk};q#zvNKV{Az|v zE7-{WrfQnCuY^02xy@`U(;Ba`9T0csQTMONkuGXa$qB8Vt5-e;ettwYT1`Sw1cH@w z6|-)^f6J3ub(Fv-3Mb9pNh{e*2GG;mi`NI_=#km zpLM-C`X2%fZN(RX;HLWzD2K0^zT4Clj59?lcHKLG%anVilY>fbzfe%?oYYWOfuPi)0t+r8*CRzkahn zxpBC6b+$y)X_tAulPZP%lYgbx*YoeQ4zwr(Cfe37N_ggg?wq8Ca`XM;v*8X49V$VS z_&7kMOHCtPM^oEA2gtl+RxAdCf_|_FMa;E_Nz@fR%@-9!^hZ$ln<$>Y{b$&Npw6&} zW?1;1A_k$bR?H?shaQ*SxjrDw?H_`Y-kCOe>Kfh`@mR=gwxC<7C-$pM#o;ZCbq98R z&fv5)b%nj72f=srambDXr39&%R$TKXbl%zBR?mN*q~RBcnJYYg8Mm@_1_; zvqj;h`Ek4G{PMPz>8+*^Y}qADIG;AP?38vGp^VdYX9&R|z-(oZbQ()qK>YN>aFZF6)iD_QLz0$SO^p#(bGFedvD+^WES-1EKy(C#m{zPt5d{xl|^fWjcF#&{;eJ6ql8C~_T_rC9(*aGR}XhMd8gSNxt>)vTo zdAao@Qu4?QMCB$kq0scluYi+NEpHyT#m35;v0oGNaxsOwNK??3O9D%gHh$9YZp^5L zbFIn|1ch5bXfSTyBIa{uj7*-Z~6Dm1uR6+Q<34Fd!gCi^RWN%Lun+oO%Z#2sM zJ`%qK4R18|_tVB4@N3X8hmMC%$56bHZF-Iq-&o~7e_ba&_l%MVaj@B?2f9nB*l)bH z?+BBw9Q>*CAXI*91Z73NUf>(cq>?)#*+GV?(nXGUs@S6CPaxoK5F+3bne_m8gMeHb zFtsN1uDh!8+8YG^xHq`h^x8qg;irj+$En!`6GCg73~Z9kWt!+(7UbEa0910OIIVwG z-{^v758bUGB}Pr_UsM=>7yniFKui42Hy^9Ck{JscBL1Myu6EFJcpRB&e)uz@06fJb zG+QGwUT*Vx(XkB>W>$G#9iugm9eI_T>2KRq8XHq`>vUMI|6*9Fl|a=YS+*pzNJhiG zX6GIN8W-4i^RYHr=whnh{+0lJy57OxnTTi}srd5UJ;n9FIvB}K=TVRyKWKgeh@|Jt zkV%7e)@sgvDzvRce9Pb>VzLaowZ?5Xlf!(PsvJx8JWbDxP3Tk)wQ|*plCYtJC$Uqy z*y)w4@o~J-8WsIAXtd7$w})EC6b!iit$`N`gftE~uVmBxE&OY5e~^xupUKV)2myl; zPniVt`o7mI4P=ok%YWmbktF(qNw(&kHrwIY&_|d4pqWrt%7i9oPsQAJY?z{nAZGxs zWEjs zZYi;3v2Yx4CG_hun#@>o2kQ*)^goC3Xv$4w3>Q^)t%q#bxLhZ)6~5p00Sdu;T%Rkf zqo3CTTcK^_={Z@1sEy0atWS_z&l?^J=&98=UB!kJ_aNzo?Tk4-j8J@c1X5w>1z|Vs zcOUJ!cFJHlaLT}nJGsoHErcT_q#J1yi&{{rC#w87U)^xOEQtH#N6!AUP8QG9jkw() zpOZG>=Vj$au#Q3+Lj=?wHT@=5r!}EJ8UvzlI~2)ZTPp*|?k))L_gA||Ax}}B9|Ll^ zm<+ncNJ{y*^cBC|%pU$;({xkf8Gd|Y`;`N)j6e|x19gKuUlV0s z2!lca-xfLzSMEDN3h*+F5(Mx#)kDYB&SNC7T2U=BmIp4<1IiHMz6r>fo>_Kz7zamg z{j`1caz@t^v|Tj%gUbZs?^GyyKm|f*_1Pq>l|urWrGhd8;0+?Ft6B?>Yt$ z#;`d4W`@i||M=@W+r0i-i$P1B`6Y*CkWR#QlF!kp7E}gCoI0Uj^uSX+?xhclz4)xg zC~zh6p)eGlxZRBtCzl^;aip3sWR*|>ud(=@8C8fxk|u^INSFrK-&B-KiE5JglOf^x zbM5tnz8SkjqEARIs1dC-P}zj1KbyV`x*lM5EhbO*YB?0bxGva8i4_UKU=kt2W6b5IOLG)yuE2YWN3UB( z4>^zIQh3#I&mrOJtLp(^f^98XCS!kV(|j=s}nrGqb|fq;&}Mx-0kb%OgMWtD@s z>Oxh=h8{otdw7!q8GX%cLdM(D(s3*U6*%h%*ip-gS(DaIns zDS9PP3F@Zxq+sZl?2ohl#D3F#T-{VStb>8D?75tmD7LMEjf&=AL9PAX-qxNOU>l&c z^oNh#@9iH`WE!jB@@+k@w~q^es9l|*u<$#X!hjQ(ceI+@kP~i|&%6!;_<+xsC80w| zo6+t$Cu+F9_YH_Xp+KZ|OtLI$HLjjV{V-IF_^?DzuICHe!*u8w+?9Gh z4u0o((=7V%0g7vVyOi=1M318qwYF$RDAqx-$A-`!k`b*;v@q_HMrI%8_gh5YP)?-E z3NNf5Li>Zi9V8xxbiRq&f5XX&L0QNv7jYRw+>8*Cv&%ZOl{U2f5nVn9^s(_P`@!8? z-!p$l81xq^xog?;ee@P-?C^U!r^_rKkP{Y~cyW8Z0tUtOK?kS)`Q$K)Jn+jKZm(AB zVy$YCgZiDdYA|7-fD2*}F@)`VZc3zg(XU_V1!SaPr&hZa+In(hoDh)!88jdfY(Am3 zJ#?O(&v%dc3~Tri`Fr;a_eLFs;8axfP-PDt#12)zS!;VU#i>#xB78QD$2CL{fG|j< zG4q~Qh{s3GMdSe+z&VNC7nK#Ov4G5$y$_2l&-h~f>h3V&h$yJ0nRSVfK z^S$)7NwZ`uV@My1f#ea%tQX4z-7UC%q&{u#*F>E7$qYgk&6iWiltiH z5nT;gv7{RL{iIVzT<;dHXWD*on5Nt7^QLZxZX|{qjciehAL5%+b+;QP!cM~j%JKtY z{|%7cB0}LC)YW^0?nCJ^#p&`PwZ>aC-M&mS*PgH7V$Vh*`+e78e=N9rdqa^i8qv5+0DSQ;V>7d;RVIhVq zNn0H;$LQds4?u=RHhMxBHNu6%e5dr4_i38e`b>cGeHEF_@3&|M-!r;@Re=YiWg**? z%~96Yb04ntM(L6S^P_-uGH4ta9{p8H6GFB?%VX8R(HRU%$=v#P2>t5$&Pmv@&Y&(zFap;ftVNVRC1+ka z-apOdJEZkq21@0IjEzr0yJvqNfD%sGQsI-Kwyxs-hOzx~K!9i$Uh(rwd`qDumGuEE z;45}#S8UA2OqZVD1bOh!scSpmYa=cDs@-NV_u*X1bOC~C!%f17&5}jM>3(#7pftuv zv)2CNCpb`kN1nNmhieE^INCP|@Q7V^TI9=?46=E_01_<2;bO0_aK>@Ip10@hav@x_ zFkR|%k)e^~VA4ry?F|*W;>?V;6qsXYP>p03bm|nQG6G!fC8AyCvH`2x4Z4c!aLFaV z$}tdDjQYs1{KAmF{$#TvC-NE62M%W!b5MBpMaf~we2hb|G4(%Ack^nhI$z}5)#*a4 zKnA-7%O+7*)>ap_Pip@ET!1<`o^|&QXIhG&>BC#U=7!rXPTZF6)k=s0IGs8cZl4DT z@N@)B>|o9kvevvfvz!y8X&_$FdIfWEYLbT;{+&q&%}?SBsUakEN**-z!rou%%=HF( zvA<9!NQqp2RpTI0wQm9VMwaH^1s@qU9e5_ZxK&@*5};=26)NMUyZ%wjMzh5k2#s?w z?rNIG7_{52!St0U-N44^SBL)YLZWFX(n(nzbK<7`rarK)!}H#a4)H||YmHNU*R&%v z6cznag|MQXqSdQ~nC-a=7>P6GQZq&1$=~VHVbk?0c5D^pm0*5+q{yJpWpymQxu5p9 zqYIv64=62^KKLPb-cCwM+!~QO{+Q_pQ$v(t`KI(Vr7yuY!sX2D2T9PMv{!*r=NYfUjkIssG zJo$oQ6V?0hS#0a$6sdKuwIgRr8cY^kQvXPJWDi8qn>y$dx{Ng`XN6;`ES+8qDbfNM zi)*X&Q;11iPevgEmN5^A0`Tc8u zo$6dg?gQt0o_*gq5u}8L7jqm}>P3V}d2sR}QwN)h(1~@xh~gZ2srlaFr`JqD+adbI zBoR>x#)b1siT%+A(9)EBHMZEsKq3Y)pMtD^d0S}YrwwP67`UFMmCMiX$ z3?{=qi8yc&7hpLr8a++1!E2`_;!0#RgA%s?&qX-^+iF}rP}c9p%kP9I9M^N zEjrQa?;1Lwa^N#4m<)OiUN4(Sef!7;)%IUtlF_w_{IH!5zDDS|ub?Dw@@`#0WopjygSCf%X z)_)~nZ)xX{hTE6OVY;&C_xkHlk5k#+)C|n6p?Y8js3cT zqki5=MvD2tWR|mLU+1z@*BH)SrA>o`eo8bXp`u~)Oew=gL`n_lp%Bmnj3TLQIp``- z?gx$mkG?_+z_?8+j;Z#-wuQ-}8mgP5sI9rqBAJ(`341rHbmLPBiidP8NBY7fp(;Ns;YGu1uE~_9@3hZiF6jK8V)<4SlGzxDrK}D_A-*cLTNf!Sxor)4> z`Sh#8Y7n|&zSGw4;S0$?Tddiax4z)_9%O+jSG^X+ zCHZPimzh>BzE74HUfvJ`O(SSeNkyREHcVslUR0a|A?#`I_B978vVOYee2uOz;GPHUF>))<11OhxiW)onJiR}O@>Y0GByq$ls`p|tk^F> zoQ|BhKgwnq2`@I`A5x>o(1165}k_I;6{Dkf6gsEht|LdAYp?EKU5_>9ca@OI^#a1C@p^k@k zkXTIq9Nx4AmG_$Ozm0|q=OGQXJXQ;%khSaw>+4R^xc`r+b8wHVjrw)a*k)s+v28ZC zF|pewnK(@*c4OPNZ8f%?#x~Bp-*?V+{)2h0J=fmPTI>GZOOP6cv?9g}Hdom@B&4W7 ziLw1(n6R;yQr9?>l0In>bF2=yG5)ga!M7*N3Pix z$=i-uHo*v~ek~qYAN+Od1t0IrK?1esPs-p{$e%ye@DBcrg3ivP6dt$md}jI`y8fo+ zPKtdoq533cO(J-LY1l(<38N#Pf(7!ZrV8bV4{nPfVQv>((Tgui`_sfY!l)0h^@mR; z+vYJ}a3OGa%-Qu(VlU$~q(-3%PBA<&UgwTP8udc@)<#$%0ZnkNOJBh}G^t!jzl1Wcn!;JJt(?I?#fju+#i` zo8J?1>nND)-Ie(E5)JxCu+FjwZm&P0QJesjzqrTVQ!@UjS-HcVP7E;av|QMbXn-Nes);gdZm5iuACOwBp zE`bk^F~%iB|MsF&?YX#HPFo*JUh~}K~G1I1+}bei6V98K3q0meHiTrXwdw1HLd&j5--bZWJ*T}LG%6EbQc2rc{I zFM-uzs2cy&;tD@kep1b=fN#;Rs4~auAaCF0r__2%2RlxRN)l^-8!6H+ zarrdNd*?uSKU$zd-nOImwsIdE8tHo|*NC8Nu1l|XuN7IGaqU8><7WbF?#U5qATBY( z^^cV5{9N`n7AhccjU3uX@q7&9?nRC$3dQi4=*|2unyVNF$Igy!< zV9*Qfmq;Ql8=mRG@gex~h?gHynP<2Z)qTsJeMb;icj@{Fi{5uC0j%u4@`9J4SYy42 zM?{C=VZR_db@CbTRD;Z7eG$`wjv*g~aXyW9G7;Fg#;noBNMlMV<>gV@TuhLph@bg3 zvl(@t|LVL2CCz<-k7GHEW#62-$+T$*IO$vZnJ@OEI9%L%v5Lq?=Gc4*YYNE~{yme; zTb7^LTt@yVEaC)d>#kCF?r1PmunsjOUwIDqY6yy``s1S^LpA@S5xBEnjW#){bW5d< zZsGz=-qlkLoI-3N1Fu&4(t*HeO2TaoUy5z26da4%W4g$LGs2#(9?;Iyyy;nu?t*{= zoBYZ)MY9$YOG~Kh=3$HeIC=;ro4)zoUh;S@D(O#=Xp)$HlUN;3wU2WIg8%?qV9`NT zr$-T2Oq_}kue=(8$n&SZM#>h-<@LZ6EIUF!FieQkb0PbKMyBafQ8bKrtJi#%&1!|z zXc=qtz7jGigvZ$Zyc34oxZccV^NFqd8^0-dY^|m)q%#Gn=|+VQA93!pv088?tYTJF zvhF#WsMHro%J8AY&MBUTGN#k(<)xB(iqc{%*{hiNkMn<3y+FRmWT<|$tXTM>g9yz*tw1>{ry zV1CmgA_uR1roRkM1UFqUNfdE&WyLXQ4Ria_EhB=q9S2d3NaDHV0jqoz=1CFAlV={( zf`aK6I4dtYKZ573g8N3tB*OEj(_|8U2)%Aa{n@bX-%cQfG9Xw5*Bj&tl&Z7U9l+pU za`}J4w&7MV+EWv_gSqI?s5NAP{C>f*hjdmu<{bxci(zCcM0P~3d9#_6^fXH6I`6(K zKTeGc>ldh(|*&#ZB=C+en%V!)*SPxruj{RMOjzXDKd#ZC;Ny+2mJfn}DTNBx|JOf6q zz?dpqAH52h_TbyQ;_6SB3b6nzlR zscXPrkrv1JGvKk@KU*jFT5UT+UGkQ>_ziut^OF}kFy_p3^_LmX0=J>SNTuOdFODwO z5N@lorA*>i1XzugCAuiac9e~RSu82K6|=(Yg_wlCP3`qHRu3Z0(v)mkiWH{G7gf@ad zTMNsk2JSIPQJfCJQE)uSf}*~gUQJNMadGo@eO&EvRe$$VRwwsj@kQKGC+Fs6 zdX<~89b=vRMGZt4`x{CSA_7xD3n=2e7pbyS8lFM2UP2m%7a#57@^C2eowx5K?qV*zT zu@|=idQM1>eFh68C`uWlpkeH$*xw94cwyNF`a%68^0(mbhz_+Sk)C3Z-+P;-rr=;v zS@Fn?`XK|rS?o$Scr2*4iL-$x<8D#?U4YDMp(W@!W52L>35qI?*jGM9QLMZ(_pFE4 zSDO}yOO2|4?C_U{r6Xz0F^N{SEt2xsSWWNH?bkZ9IKn@a=v1UcFpa#iz1L*Qc!l7J zz9J({aO7MZIJ+D`F?nup1MJ;5%boU0Tp(iU*9CF?_cW6tOVQ*TV494ZZweyi5;{|x zC%`Y2A_lMfehMyS{o4RZc0?kQTt-3axHS54mDi-PHu)lHVEvm6MPWp{jOJt3NU#77 z8@BFFPV<`G%6Thf-8E<4%uooboxptlpx{#|Z(YC8D-i?|npV&n2jZIX>2KJTw~%fs zu3kgviWVjqpE#ZWXrZwwoQc#f2ET_p-KykHwjgpMMk($sMzvQ*CW&+5ijE zaSY4-wbcXF)~!3YBWE@;gf;nD9ETX-rIjLI855EimZvW_{Q|SpLq4Ql{E}<`<&PAD z;3<{jR3*8hEPbwI5aMt~RgX-=HHTIYE<|~wn1=-h(FK|)QZV{4UBEZdiR z-s6eGQ1MFk%%g#q?08oN#l=GZ2{<;D63Jh}aP~tEdj8_!D3euE$5yGK%?h^_WUmmo zD-Wf%eX0w2gF3OdO5YK(P4EZUA4Sm%p%SsQIXQHzE*;7$Oi}@^xR}8emx3OQJ4(&E zfk7LKHgnB;k>B`ZVUth0$xg@T1hHY-(SHZcmT`+vQFlrY0a%L4JV+iau!$x0-mey8 zCqM#6pQsg6AYEp#{5E`yAr*)|nAAM{fJ%rta0@SyZ&`M~&qm%MMm^mZ;d4Umn*vsL zUi%|py5Yj07*YILpMNsc$2zN8OC&*E(mX0QlOa7Nz(t_J(~==wA?|E2Z#z70l7Uyx zF*1U#rn?Zxq3WKTd-4-YSc^CKyga;#CXb3QpZ(G;(o|77;lqBY((parm^$ThKMA6#x(98s4H4#J!Zd>QOF z`BPG9fI1C}h6Mg5ayEb`Iik32YJonK=N80>##UkA2}7C zNFiko-M-Q5$2M@0+m1PoAPzO;;>5-Un^5TKT6*RBN*w_MA14CwqR1ih8>9AR)P!dzE+EhbI-Ei)v_3O^NAS6ow{%8 zE^R7`2_mV@=Wr*pOlV1qpm&r=G&dFYCJKOg@VK%6mh~ZWv(Pa>2E0-G3Z)K3i)g2J zG#f7!sC9WGU6FkvlXz93pQ}{9cY-$zgME+DCOHK8FR-iSJFt2rO^SwWX2(Ss_D69k zx^QZ#lAA=*ZPyZJIz}q8-Iq(2!XG#N&IE=eTUE4K$?r~nvFIO(n*aUd47&cc2^@jh z1joT-q{BqR{{jktrO`9%RkAjCckAKXzi=z0e+Lw#Us^HBkT9nuooAIM+4j+to=D>| zt~ctXXTXoec@(1H42xpm7N?3p*F1e4BLxt>Hx)jS$;Qq}B;_V(9s`;<^gnXk|Knez zF%8f|rSnISZAR31?N4+08R^fEFgRl-e#f4HizPL;Gfb_pLhO&@Ei9NExq&bepgi=V zG;|~HxVa_k6UF!a-&kDgsm1N9#rXN7?Csx;-OKQ6^T}Rb0X2SQ0}bP+BBx10g_~=o zr1(J7f9ee|p87qX1NZ;dn(W(ZtmU4;H?QHu7J17f1%j-(-%%9$7wS8izt@*1mg$z) z#gVSXIYZzqrTWH#o+N68xE8-2X3dK#(IZ$#HbYU?KU_d7C}=| z)gf?8s3b|5((>&RAwN;^T0#XACAkf+j&_lxJ^OwR(joAXDMZO z>b=a~uycj9^S9UDfr_#r+LgSy{`{@XVxZV_?5b|cJ{m*pPZ z2mmFAplrS7_cmwCf!Bbg9(kG!aw7R2nQFeDZi~qUUui#w`d5qVI}36Mh_~o68L1`_u9|KJ zND0uFTPw!Q^sX$+4jB~E@_^ZyG*y}Fc!~p&V_|kZ6!E$dcmyd5-ul|b&ip5nTKhWb z(5tzbQ*bf6ok?zO(~L8Lp6b#y5-Qa>s7TJWH@F&R<}Kcpcm7wJ)M){#;yq*ZB$Xn5 zaqI#`|SI365D+Fk~9d6v6K>J$semBL}6PH4PjX6*mhJskTCTQVAwBfxoM zDXMeW6S64zH43@!r&N(|;~MvsWh8Q+cHbJ($`|fJ>wg#0bcOufaT5OfDazpm7E)dA z!DU{BY0Vq3p+xNlfK~1Oaj`Qm{p%S*?m<}G^JoRq%T5@0EUPF@f;jBy=sWwJM9R1T zP`D)4Lua!hi1A614lxFAJleT@gYETQ?R^Pu-`Vv$6ry0n)7uBjuNO37RhQHDBuzc= z)ZZ)q{yG}mvOSl|9?j(1D|_Rsw=6E;uQ12GI02WLfl!(yb?ON~G9Du{2ttsMIt8$* z29g}vAJ*nt3&_$RE_rCYs!soP5M1a#44MI7-!K{5?!(pz9DcwjTKqf8LJGj~|H zqWIi`LU`8Ejeb%6%BGgUjU_W`bxcdnG9qca& zEtOj-s1H4>m1oa!iJAEO)HKk&@%ph@!7E+?rpzI7fwrsPkiH8B$fErLDu}uK9O9%-nDi8~g!!q=Qt{Sc#_=7)>p$$drm(?Q6B&i+T8R zdn1F4v0%>_rSV$WjVb0mXWzb9R)e2a;XGLeS8kKez^-ufdoEZ866RtXdDz(pvW@(n z()wQm&R?xm)sj{9A5<+EZq()IYq6zeYd!T4q{ud{kg=L%e~fYj^_;Ki;sbebYiD%C zH=%oNy%Q!|Wj%a^?15GPbjA&aua4hZ4&Mhc^-oC1xJNF+SSvQM#z(B*y8`2 z&XpN&4o_lwTDW4PyxsV3t`imY-EVvgJJ*Mm)949(6~SD`!;{>+Uy34dT%IyM9J$Zr z8_XtQ!sY8M8VAJGz%fNUh+)(+QpyB#lOV|AdQ-~Q5rQc`hWmber#`>LTu#hd@aJgR znA1Vlsd=8h|IzOXS!fg2@CL5Z>|WHW8saHoS9qCkQI5m-(Iq|y-&Y>{%4Zj5FeF(1 zD&0rCb-xbF!;PN{Db^xa9^wbh4xOL&LQ?1{Qb%*R9GX#feT%{L@RN1+7`>&g_p(%MFFm9NBY##ePzXb zgIDq9RYBzhF1X3*Qw%$LZ(G$>A!u$k`iaeA}?b_xW+s!~%YQk}#o| zm||<7swePfpseakqB=H^kPMh}ShkMzk-9&^#u|RgV1$!AE~s1{T3N@o*tD2$KkVHz;@K_=9L^1J;6KD};d}BW< z8MWfpxEdu}fB&&1L`E~(GAl8%ooh9nj6u=Bo7GiieN}_|CG_4DweM$$`)G+w%kbC) zC8-1u9u2p^o!2%OWzD`#zo6FBIX=_8x#1#LM9<`A1=ZZs*v!p zP}J~{@L!I!0VXp&i)I>Pyq=nkSD>oxaFzu(Nx7TBeW;=IB5q|zzcHM+Of>_qg(a|( zK>pldvd3w88%yBr-qES`U+Wa*UqClURfPHNG8JxV*++u5~I)^$yF09FBhTZf?=AIwZ`Yy^EEfN&3Ny4Zc7z zF{$UWv#>qsr{ETB9L^`L5J@_2SXHTUEU|gPu z(D;(%3DO4!F_!>=7tku{EkyRC;UdfZoibKTXYO$!R*9}kCH%(6V+leSIA^xd%PwQ; zd3SY^YAUdZh=~ZSM0Irj+{|;Hvc!zGn*|TJg1n5Da>a}746>I#nMB=~F;RfEOcoo< z*?Had>I|hKEq2vUSh0$`c%RC8XvFXRbzIfW%U?TTb=;VXVlFLyS1!FfOX^+JL?Gf$ zeCUG7O8X^tm}^PSr80_1eNy)#z5yhE7Dmbqe&a%ecoazqq7&yRFC$czC0MGP-5+-1 zz78_jJ)*e1N)j*I^LCym!kQv^ea0B~S>9z6p}qYldyGwua&hOa*^3qciWm};#H31XB0VS8fnLM7j7tKWY-Hc%hpk_!`MPwDY& zY|`sN?%@1UUR&R6U!|?BP1pqpI2s>kF}4%%QH5rjN*dfg2CjV?a#H%N9~)yQO$o6u zTeWyuIMKO6Sry-ifyb``95hfs`>tU2pEgcvoKjxo;{8i<57G?3X1tN8&Dtc>$`U!D zH;Kzp$nAerhR!5pPy7mKH{KN{j;-!LJ2!;$7S_O3?(NY#&pB`_H+Yjt_fD^RW@ zH~o{Q?p`(Vpe((qM-(hXql&erGdx>SJT>x?c@Tb76W=Eop!MSS?kbFM^t4RYRh|1Q z3I39qGyB-1{V$QwKNQtj2e=MU-(d8@qVs?@#h;Qp7eKAJQ0G@#*^{iJW%#SulIUw< z2w}1UL4hj0H%70;s{`7BU<3SJ0bfRc@gHJ?gVd)a-+U@41Fu|=)I}56^h=G1T-Tw< z&00(#Di(u3(5e&}BX#K5Z;23NgSi)(^D169YiOcOd+T1%9ex)yLfrFP`4|?M6!Az% zX6`xz-fkrq&l}S!d?)*A;7mrZ+QgdK+lq!m*;>s2nrzW!5?!j;*$5ETs18j`k zsThWBr>4+x#eNh9_n4}us&l|LT#((s4T5ej!VN>g{vrSGHIO@eYH$}~nOa*vI!t<|iu*E_%ODo4$e3gU$m3cXwIG(DDeZ}1P$0KJ$$ITN;Dt9wBgPSI z`dNY6`;-F=dF%uM4O84-cPQ(glLWBTNJ4hppWnN2KWiAzv4N;rO|UxOm;!p|VJw`= zs=N2s^L~tNDiU7m6_F9K9mv4L<+bipC6YQz@kPA-E7M`@OZ91t*3vAwABq0>`I?fg zN@JzuG^4<)CQHVfNZoS_aHbcYafo>*WsFm`#W-1R?@hlfmC3qqX8XOg2(mo zo#9k=qt^+SCF@h9e>m!!bJPT?b_qh)0-=<(`>dj~CaVHqIrLcm$W38{mmr?@h)mTV z(9bl;*sl(vf<*iW`+MC~;=}Zs#k1|jy}O{#5V{lCgcV=A32rw}w5SxANMDkmI;!dh z0nML*p^H~97bwCUJr5-ar(l`sJxjnwQTWpn!YKUE-gpM`CDl(#?#i{C zdjB}F7IDDrQKjAO3g;}i?2HGOohfu4!7oZ%vGJrV9%VN-|13D{+1ShnT})mgLd5W(?X0QU^*vv z6j0uvakK7gE5xcd?Thk%J}~W9knO=6|4?M_j4BPem4?L3U97WH3_!}C*Iee~eUwz3uh{gu~#;^)u; zGsI*kd&kx;{v39?x@bG0t=H1Fx4j+l9T?Aq!0JH%I&bHzoLn*%WO15L`TS-e_<2T7 zK!7_P5mcUTbMIx0RqCx1SD(qfKKG0*N`lq7&APN*P80@vayJ;^2NMz=rJy#iK8!E8 z5=)Gafd)h1KdueuP~dy;J2#el6KkVSAHszH-5_qJ7-au(T=7+lq$iCw-}=Y1B#o~T z6<5v_?&u=yHb28`hq4C~B(755zql&MkT|^<8}fj%+#~$Fs;}XjY%b71)YE5gqVV^x3`i-bW_XByn&%nF(jX=atmg<+{8&=HvA?cSP$LPYF3x;y zFFawf!=#zoz8z(WV85yQ>UB=I_M%-R#@TZNutCmHYBuy6E$ydOHqdM^xxn0tCBLY^ z^M|o8XcEfxeG+$HC96G}!X8bOzW9kze%%9N8U4s*Pnrq8c{;|JU|q<2UbMU zh(@HVFL#iVuJCi|Ru~`TT<|kfw>b-4Z^36?*Np?<*B&R@bz#Pe%Ir%U);l9gji3%X zbmh3ilEK^ax(66rO6PKD69Bjw`JbP_L>i$p?67fVLotJ3^A~zKs{6H>SGA+kH?&_+ zGb2)GQg|fd=0ai(@vOhECE}N?ZNkw$3_$Zf-%`|ft@v=KV{yTocgZNh&QJZ7n^HIJ zlgmbd{_}Q18F26W%V`U%KQL6Sd&7-**8Z!D8$rD? zZe!}Gu`_OB@1-S?6wZV2abqA{?t}}x0cMYp6nH1VeR22GP6lI^ZoPgIiH!|z-ldvdd zIz%87ZfcNZC9Y_&i1;XOAl@E1AKnz~Hkxyg4B4IB-V6GiK9PB&_}Ni^A>C`%$dj_` zJUVai0k9$G138kh1t$_d8cSD!Taj&HP4g^@iKL>=Ob z-w?11X?2iVL!y&we>H`2+N&gDnnCJDQd$@isGiPUrC4NyRxjet~5EIT`M;!1} zMuioWLuxVcm_lT=KPP45S`-!fviSL~bX!F;jk-{)qi131dbJzl=HAH{uy_b?7Yb*8 zy~OD#mPnM>6iliCG_c()d|$!uOY*t4oleygfb{bxwLZTh z#r}e5N%PH;-Q3^gUg=f}LX7J;j(8jn5g*Ollz-A1T;d)DOjr*xg0nsPyds zMPt!pFY-!tef698B6~p{A;sQr9W7NKb&ax6C|&{~ObJ+4CMx?!b&c=MIp7_52&w#M znvS$KA%Z>h^ZVFOyi+}Rt8Xzl>uCQoP%L^@+@D^ba7Hy=9?=#wM1zGruah)H|rYV`3h_@|bW zPyiDpetipESS#}%-08$qJxQ+=BQ{SOopL8i{E%EU|GbZWUO>1DR#PUGp=^vQ^#Y&# zmv3X1`>sK&*Cmj`UH}ZecIF{f;Itg#@}u65D-s9f_orNQD8Wu^yMAOMBHgSv&Jtt= zo_Jg7> zHQ+>%6OP<|0-j0#@X5IF41s4y#cffT_wJ(@$8CiDGyy0Ym+2IP1$W?angI&XvV*h! z5s7#N0_Ouq$IMWq)@1uLr&i1Sc(%EIa0Xt)1FM1)L$`(c@(;cM8ko%NjEZxq>1`>2L=OHkQpxpZp96Omr%M{z)R$vHJwrn;kbWC zbiY-L$z!M?a3&Ym&q8G`J!M(Www05IM= zImYqBN;&sz@-1N=-UzRJkGtUqYPq6N*D?{euF%}33jhr>JR)gR$vQSt2#D_(>)#*6 zPW}D57hYc)N;_j*q55HRUnPzD#OGa{sDGIqjd z)%!zEEspZ1s8l*P9{bB3efDke{3e*+s*BgC`efNz0|=QV(*g0I`xa zEp=xT7wF5@$BWRizY1(5{q}bPpjX}Z>HU4#C+TlC?;l1AlL1W%5D>|~0xZNKX!==O zFp3~s9CfkyG#mmdtf{j-@4muIUHFOx1+UvK6G!o}Bc1y*^^lNqHafL%W(og|&FpAAoxNd8(t=-Kz>yi}e4vKXQst0|~#L5w%)^3$!1r7sXo zh#pR4GdATa$C$AFjlS4PDCKsC&u&qNt`~jfi(7KZE9`<0%>a0d`s?My;YnL{j84-P zm|l&d{}D2Qx@B7|yU;IhF!K-EeuY9zb*BF z3$4TEn37uJgx7$40E+gD1@yTwOWpOU@T}Oes0sQel5}m9;H! z;V~-pp$q{KtAhpTqTr=<6d1Aq)3?oBJa~nXt7!y<=07qoHmL{}I`^hgh2!Xr(No=& zQchr^tz6#*qVp%~Qm;(*azXHeFN2>yI?}^=xL1?r2MS`;9 z4gVsiqq6YKE_FhAyH&(kmFyaWIZyZO#@9qqSkuPLtPTO(O}XBTtbyyjMyl)Bp)vYv zlVkrrw&K!&=^YUM>83ijbQ9GqzljePX5fC5jsvG7DLJe7juEF|BQOe57kxV_EzHMY zWLvP;YdwdZ$j||V!~xAthf4=#K$Hd%P~qxCd*oSbOIm*dMVdH`nQ^wgp59p<%6ZxN ziMsn$K@})GVz$ZSsr<4nLu4^bsZ9M%@Hn3FH0H_oR@q&6PyQh;e$CvK{&?@tG}OY< z+igZgE#*hK$xH`JktJ%rn}Yr1w*FT&`Gv&Ch}f@qmqV7p?t!eZpOfPa_x`(v1m4hS zJSN;CMs5-um6I)q)}@J{Nb2BOIqUv^^rJx9?HP!{;R4?Q^J)zb>~{N#;=FK0z9SYR97-9}nm@;q{rF6jRoQaC;l@*Rw7=Nm zVz?m##Z+?-W?=uO@tbPS^m)*>{GkukhQCD5Mdh}rE5KZMN|PT~H)3Lko$RMJ~ko)Kv0$F)E!me=4YDPt=tT^ba;6q1)@k6|jf2W<5 z0Ipzz+udO}q%4id*z+h*|Bsbn7^OWEN8E915ns;HkyBw46s@6U0%zE$F>!rW_Q*rRf z4Z7WB_BLBApx3h&rpB8heoCv6M>p_Wb953erB_X3?#x=uZr8BkO5Co1&&>C!vzyj^ z+~zvw7JKOpLkcF9_g4jxbP@Aar(4VK+5Z%xHe4(OQ(D#;NwHTxeo+)9JlWONVo#{; zU^1dypwr)tQnzL zhTxG1Ha>#G>n7$37*9-Cfec%QQ85MDL&GFrFVf^eR*YN~{H6JfYFeA|ktZQDLdk() zLHI^vBs|ow^CT)y8G5s=Vc-fxPN9u7&fe!Z55Fr)IFm=c;uajAX^_gp>}+v|7Uy!C}YYl8)ZtPBrz zJXe)^8g#L&YUl0mYofK0S@ZW`4ajVfM`>!=;^;Pk*=7eT#$d+nyCWmBgVKysw27c--3#IhO-usrxuI+pUNj=Fj?y1qyWSD$_o9jrr{QTN~;w6|t&AthmNRm5N?8&I2v;C(pXEc%BpJ_B0A4tY) zTc8YCCUjC%z=kT&*IC=rfKE+q^YxU}3C&a&z=p{zNW}8`@3h4VG7yVLEGQ-pJ}k*w zlvzu>$gM9BL@u|S@?vqiGRtkb>`|fFwC-6T_ zt|ki)+%F!YI93k1X!)ocEiDZC)MIsjXr8_OIcN6wXX1a)=uJ*R$Mo-$~_+iZ;&Ak&^oX3wE9ZDWz!Ba>opI|au` zxC1*1UN_<4zpcrB>==qYY^SIT)k^IJGuOTU?xtlDr1SlxT(ObpW?O){e=vcz@jn>- zA!lE_rfpouYW|k8h0UzzEIl?ozkJD-^}FbtVb5mxHZ0SC-7s^4n$jC5SBvP2zIY%V z9j$`(bc5-lbsSdpaqEuLYdhk*c#l$W@DHw)pK<#L5U=-_gDi@&o^K`U^TEv3+#)+Ljk#>q$55>mP_ zBnYVmC&V}xMn})3%b~-5piIHE> zqp2l0^_F2s#wV&HuqV$eDM7LXLJZW@4J-UZw)Sioe$T*fXgQaD&QF2X=wpIGq z2kXy2ebWVeZVFPyH}M&c;UphAzNx*}s986!0&}7&@-R*q$5eEc5n?;aj@FKr)F=>``6{?$|W`Huwu1{d7K=pW_KK}0!H4E<&sT7_nF zbiK`*_)VSQcdvK^kO9NVUTmJbkEWL})wyVPIDi9d)vdciFf=N(W5};wE{mvI<_{k4ZLl_e zML;V03}fX11W!&Wz_oRyL(u1EE;U={=}AI1i1qEZY`e~3ywx>8*@YCHn5%reznNW7 zTW(B~gXg7{u`LQ>*zr9(;hTCL=dU4TG_3^f1#-cl1XBLp^AQBJ=+9qIk<2HK7xiQn zd>tBq6K%;MA9jebz~IQESg3!Yu|x6dhm{MzF5efRV%HGt>W%2j4}RRbyN*W7WF-ZX zRw^r=iwTFl|F6jXKUZSA(YgjSQ!<`nNBi2Zevz25u_=9BR` zX7w0{6oIU%1w7$nQY8X-VS$5B2qJrfH+o2j zei`|tPji2uff_VZ1QIy`+M4gXMg6Qy@|)Gp8=tY<tEo;*=eKO%D_(NFt+5*-Z}9Nz9-U!m~a(`4covw_|n~hTFr^{@7#^oq(U|CIy|i($Cl>r^B8SmvJ(;OFYTB)=kiX z8HJ=Z*yboSQg^dGiJC-Z49CGoLm?07A>z8_qwl{@B^in_5|sehoeuUdtMu~`jh;Wl z77q%u_Pzd;8LfG<8!~Diy1yd3oq=G)aOWDb)B4Zj-LazXm(F81be5nqz8PEP1xy}U z9G0}rYLLM^%#{$szle*Y$2aA>#xQyfE=#oJk>Zv1`Zw3_t$m<`t?S!4#>!5#ZF?(J zmShgL!?lwK#SwW(UjMPhe@DOw=atbr1+0m;#1K+Ege7Q|REXQ+26KmAfU`QC1RIn| zOpgjN=G!{{D!iNlZ>3oi|E?Cl)`6Aa1?9}qP`yG{KSnNZvs+F4KGwRp>;y}{frAdT z3d8A2@Bd+*ogY0*h*@gt;!vxa8;;y)NgQ$!eh1fI2i&Gj8PYyT;bd?Rr90(SuOpzWlBE z820{n8jCM4qy8eegI6cwS%8OlRCaPd13z+y$`gc%GD@dw;`i|WihMT;W}4V9XD>X6 zD^URGG^w#nEbiEI*8nL`{alqOy{;t)-`V86CGZ^2?+69uNq<&~LR$c@6S z;_NqnYgM%PiAX_v-Ffpu*GxOy=D2b;%N~$kCYiqy<69-$RSRC&tcWlR9s+dB z6cue%LQAVpcfr?wV=O`)2ZZ|kF6SO7&{|P;@oe=Z>tbIgj469GocYuX+ z%9Gv1)|5c=&BUvNs^IA;l&0gK*p5!742Sk_My%QX{&mIlodEhy=_Lbk6dm_`=B*5t z4)ImSO}|s%h1UVn3fEsd;)mDOYp<@d>C}z8n><(@wLe`{28vsg+DEYwa(f66={%#i zl7eQ!!;4-s)HH10#q!`NssN{Cyj1NioVN8F%MzUAbFXgPS0QMuu~g&7Y*#>l>24@w ze8gKyjWM=v-FIwZhfSUqL1;jArgQ5o69*9jDkyIoP1m91K1QdkPtSjTl}8h{Y%Plk zg6#%=o=S1@m?TqG_BEx=4??h-tES}!G!=$!7WHr_2}r8Y6=>S_RTR+%+{ww0aJFE~ zZv9FgX`*eM2wS)>jj4Bn6c(k;t`yWs9ekK-c9tIBQ z_#4t*-+>+u8}47gdcv-|h@hWVAKdOk3G{4nD=1x>@vuhCs(tNLs)P}%A zN4|GWq@dV8R18cM2l(Dyiwd7966c?$t8EctW{~^(W9Ya-qxA@v`mbqcUjI<8X=PvK z2exMaJ^FR!HQY*NhwO-fKOp+ze+3@8e~wS5EiD?Vv;a5DDiF+N1{5u6nVN5<3X22r z%_~qYG%q;q))}j$993hh*W7iWH>_^KHP z3Sm1BDKA8dtF`&J=$v4QZ^-W8bweehRr)@sSeqps)R2+RGX==Yeno0X#?3#&nuhoK7E(5{7z zzju{+zP&NgUA;LIUe*!2LjzuvCbyIY8U`5f2+}%-q2k;QQQfoy@6>=wnfZs}?0f*^ z1gvo=a-WZr{wee;MN3!+wLuAT3|a0m&?~tjO1LQ>Lc|$8UoL(Css`Q$D-RNIpmZW+ zG^T^W05~6_WFkx-yjywig>tzv%3bWbov|v|kw6q^zw33{Y6@vUr!*H@^FSR<*?GTC{^XFP_O1Jd%`vZy19KZ4NF5&7*> zgo_akTzY5%t?YW)WiO~L>_9Ws`Gd#KywDA|k&&uM4zbK0sdT^6krJ|K7&)|gvM<)U zHvSE&#doM^X-7@m4Br+-=N-&0%!M(8*NN=~1kCbx>`{S1_JY?;np+$#kY!E6-|7y! z_8IH|7Uv+6K$%1k7Q0l4<-NDjGi#uT{0)?#Kp-t2L}#AT+2I2p_?V3(_6cQcm;bfr zB{zqT=2q4J(!cJ_p*W_q8u)=@O#NdRRkaTHV;ny%zrQ@#BhtH$z~nDk%+(cr4+QuP*UVKbl$G?Qv1rc{Q6fdc|+q~ zjYb6lFQ9vHA1kKUkmD3PNdoq!Y63mTJavYA%bZ5x=gO4o;3cwk>;A#T;9t^{<=a6Zj#I!QHdj}(lBbIp^&SeyihP5=gF|8+*C?4VQP)Pp(&IyR~L{+(~fny*3}wYz+I$ zKrE(Gi@$wu3upGrEV)LgT{a7uk$=k#{f`KIvvnS=eYm2M)zCQX?(eUxo58+AIJ=D5 z$)=0EFtL#pBiPixAyu=d4GMxoa;&3A=(|sa5vO{tk;Nl$&f~0DF~0`i`EZE?T%GPk zu51sU$vIs2M?3kfLC25~lU`CMo36uN5wvb#Qv5^2YYUQO(6#aXZ<#`gI~A4auP=Fc z=By^+F3o$GOT0?<=Jv!#%2Rls2uigQm;$8HShRk-yh^*l0!_6p{Wyxlzd%&sRN;u2 zQaMexB9{i0x|K~67k|(GRvZeVp(&-b9;~3`wU}w z9G@%>FQtsee+A$*)WVNHYY`GhK|_xp`7_7Vc~Z0KvLg4;GM&t^u)1DjITqM>r^-s82^9HX`k;fgOEjq)e7-fG_1X4(y<<2^?L#n z7>PoXReG`5}CkbE~U4igZ(aZ)>=6+2XRq!n_BwCXBu`Dn35&vN!y&&|7h2 z9Z>$F@L+{Yl(I81!l+Vk5n(V^csLLf#4w6lc6qaSSa|r6%#+5IlC>Az^BinBDiR8O z8CWzvhg>7-5IUr3AF$&o|JeNt=ZZuEUl_OQ54vzzVb~L)_&sp1MJEY8aPKQ2RvqTb zFmS(Ff}e;UOjn_|jF&7XxAsDwnPp&wXvNDPy?18%(Bg;F$COSEs_YGKX{V10aBI~Hp!GzEW?2}7~u^z!5};yh?z`3eyxWCEiX3NMyJj`DDR z8ffq%5nnzt$qG}N#N=$>(^Tw#AVfze~lhf4Glm;EWS>IAZhf- z+kl+0I(49sdZOl?4^j8U=5SIoK$4_~Y^U(+P;g&4E7R8}Qa{D_qL$15_ns@VMh#n< zI(+bupuy}X4g%#b0SDgcMH=)m)%4+_R-GE`6`SI%{P1VSuIWavV9EetToKgn&0Ex5 zDGV&$qM1h z(ED0L{yV**!)_7<#`%5GN!m}GMEO6TM{DD8Z9SiUj8_60JAlhi?QZ{K*6P&^vxH0n z*~%dsoY^~)Km0JdYTL^|c~#9k>y ziJ9RQHnKbKt4B{2LnbsDi7oT?E9HSlorup)IIgeNk zO#z>8?5gt^@`Q&7{c$KP{Br~#nY=}=!tVl&Wnz+i?FGKegO$wm%)0eg7(yfs2T5f~ zpP;5cZ+$3xzF3UMT}dl7<5MzMcj-^z;2<(49+F0?Gld2{eZ+++{9TRWzk}6{nz{S? z482w(z5&o^*HP-$Y(VY1ABUHk0a$6b%QsB;+k4GAPStJGmVu>{#>V3F17nsCAkkAt^Mp_J$qrXqcp{>|ia*>lB(W&xrx|4)_knau;pP(gND=}fu06xjeIpTrjbPhhI5SaBV0(shNQuv_-&H|j$Clw zc;J-pH~(~s%N&g>di-dJk}EK5-yaFcpDIGl=|j}4NWjlD?b?e2FTNRGY6jqdEy{LD zS=N+Y(vl@QrNVkvQJ_DmfR!HUFIFyFI4P;P_@V5HV`l|d_NEg!SuJ>O_P?oJvF1oz z0EW}ZE+3uf`Hjf^klQuRBmR4=t^K>De_kCHz8Dod zHvsMS(pM^%Et;1)bnw!&QNzoEDtp6_3R8~vJPXu(+DoD5aF>+ekdCPe4kn7 zy&ff7jAS-<|1_rk)8ru=d<{@Mr#mY@dm`p-?~9^jmKtmw4SVjr+)06j=GZ4aH1%6V zX08^(G0}jbCpTrFcknxnNY=hoE>9si%xUyxl)9(P@HKaimB}bfD&hBtUiDB3by_?Z z7`ZB7DIdM!uC(*6tc|lWyuXEs^2r_rawdPAx3==kdDb`y{A;yU`4m1Gy z+jcDo&AxaUrE#Z)_e{;$ze++G4#YZ@oKo{HpK*AzSnh}4CIaF^A>=zFsc6A@Zb)S{ z9DppN_PvjBY|RFcWHekN0qZ4nURCzQ2ep#V8>l{`v<$2u^;)~)7l|E*8gEUXF!onT zMSU}a0<$}cHCMbMY71K8rv{`h-l##s$l`65Gy%i{sX1i)>`l|h>9t~+AJ!LC^Q)wn zlO7_LCQ@^2CwO?q?*&1qL-xPjRpj}Ie^cQBQ!um3)8=8YB;Hh*@(H#!DBjJ#SsU+Z z8XE%^03}ztFVb7{39$Paps7OL8Yo6qe}RAU$H-FfjVDBij^8lNMG_%%VzS8PMvN92 z^c~eBn79&Z06D)e4Ckkm08!C_&6w2=nDs~_OYe+k8mi1b}RMRxvv z7xv^cqV8Fvbl|((`lE!HvV|(1}Q{^o!zNb z&Cf^Y3l;gIVK8Umlg1;3J*N%N)Nd*1Q}z^np2*VU0R?4bZq^h)_+@ zTe4NNxU*7!O$FwJ2U6c@z@(p?8z=W2YY>vOR!tkOGjxPxndYyQC+hl?uq^_P3A`sp z%o6=IkUJh2ev5lfqvk4+RmgC#Qp!q&D447qVPr-3>8e%e;XNhXbyj#{2&(T*!ruTr z&l$skggkY|sH=WhvWpiHT|9qXozc_D*91+tW${X~C~|>Njjb&B_m8Z&zu|`_;PY zhfm0|bh9isyglJ>8{1XCrNe{%ZU-HPV6G-Bmo2(1t#tU(wBdt?1rBC+6l-1&?0XSt z-fu1?SfkZm1H_dm8H7$4Dc4?8&H4E|74hR^u^pJM<(DxmFZ~cJ)%wlep(O!FNW|V!uQZWR%2a@sCor$-&Pi zi}hfLOKWhuUtt1W5v9>r`c1JfT+1tIthUb9HdH?I z5>6ioFR>^fzZV7DO=VB4s`Kwgp|L{rO(oENu;FY`mS2df`qPIuWQ`yD+dcz|`vzS0 zh8Tqw7HfW2eDD;~IZJxI2FP5UHdru3N5{EW2XQWqyF}4lf5Li9>7V$c?%8H_TSNw7 z{g=j6Jr8k(aB?gVlK>D9OaqH$VDvhSjHwBAqoTfYCyG!|#;~665a`ZO;gK)YhYDR= zA^wR51dTZ!)-VI`Z0?+2opPofu?K=LQ>oxFF0dD6v zKxb*#v<=m7z8h}um28u-=y+@UQ{iB4cU7_F!BVm54*d6_bX$AV9T{Uvf0~e&lNxxY zAi=)}0oH#DHZ-GR+}0yHX@D6`BxU3uen<&4XUHvBfUgpgDFITucz>LS&-Q6tv>f*T zfK2WOOkWBlWSwiV`Xf=d&R2;YomA+vS;c!b3`iSv?$Op007c7U;(e$CavtfGb;XiPc~gZEM_#9Jux$sUzLX+h$n~Nul53qgdYriCRc~6M z)?jq(>s@-I2`s0P%il7?hpry2vrQsVg^cccfWdkBV>z4<0NbgK<6rK=!PnjncUc_j z@>g~_;h}I+GdOP#%Y)_R$5Qdwy%YKr_We!Pq_J~sG0}nPia#D620Rq@uvl|1%e3+J zF*3`)6Kt)J9TxTcV5+SLsCKS&?ehao@Umn7@RsYhaRp%jvi8{IpLOq@;UeO4j97?S zA#yARvM2QP05DXj5XbKHFHEXN_dEny$eNfndKeh~IvPYsO--L#KSK{({uE%?jqYpB z@%y8M3fBkkan*Y4k=CB_J5K7ll;w)DKNN-rX;={|LYfJ!g?pfI1~BvnAa#J&t@mh; zMV+f&cpWGARfW}i1xVGM==j=%hRluOq-L-TEEQX>;*rI3Qb!C}nm&5?SX;D;c)Ghb zm152HK=p^fJ{D`XunH&cMSdB>$2R`|36eekxA+``3wH-KfOvABD=fK1Y-YUS5 z7{|+yQR(gH#zwEq_J0U|BqNH0#E~HmcS3`AAlzSn`O75e>{jG?l~90ffo#8IS{2v@(S0?Z_dC6+=@E}K9#%&f!_w~0`J zLwIv0MZ>}O18r5`_ekJKR(pb}-AVfy5i;c;%|rt7&+FbN4J=}@4!s-NnsHjpiJprg zUk3`N31UuXp$CQ3FjXrp>I*G&ZKO5`F&KPxNEq7{Td}BV^|snH*&nxzdK>rlo+XF>$Tfw3=a;tq9<0y5h^^gM*EPYFJ005pwxSe62B{dep8$e zy>Uao-aS#k(PzUh5h`S%?_iTNe9go9_Yi470=}wGSsIc)oA*>;|MJ(tFkzVG9lJgL z<_UjWQ6J`UbnD(Su)5T-|KIoLM@xMcXO07A(XLvB^032Ecw6d;Z2!+2d5?Dqj0Vk_O zIW2!MJM>--yj)}!y5m=4X)cBe*{&t#*8s!8EdE_Q*R!`>!&#C{^x!LRp=sydaC@&h zCCGR8iHUi7@M9|tmHKNLSO5+@v3NvmR_-sd#+F_c-6t_R;J7uhGE9Ny&5&vEktzxw zPA<@=NEjedG3RF5-XicwMos@$vnKS$@n9q7%2(-{&UP{1rg8(~bR@yv%nZV>$RPn7 zd{0m`D0Bw~6zV;9ig&}7Z1D^clDa|*A(K9f9J>=oO8v1Adi?0MA}<=rE13;QzC6yA zzU8=kE!czRSEToKE0)y3*e z!-}A9daYb{kYZr%08S7XY(gQ1K_UDs>4{x&HywIXXkfAap3#IK-MmS_l%IDW8S4+y z!>Sk6L9lvYrY5Npya~B>7@Doyph4(P0`jJa3{g)87Q=JY6Gic+1;00K9^yvEUY78vC!_XFSSV4PVB%t4go-tqSi)(#!ZRkqEu>Kzl zfO8EULZgxem02f!(}w^6AOJ~3K~#s*9}-lCj!Lcs1}x~#E2hlL4phDY?0rGIaI3%T zZ9N~H255}4&S;22gB&agMJxXMQrNv$GH^(earM5&w9VHoU)~vGw z>j5gIKveuR7#<`a6AwKj-u{&j?=2!_-y!r`ZGTdbO&V3y8d&t?kY6t7>`e(Mx!QYq z6QvI1L4aU)y@laHdasyZ;kpl5gR;TlG4+GGgOnG;ZV(<#hWMR@URZju4y-aCv8vu{ zVf6O7mi;dR244g8=^K*K63~9|^|#TqV^7$7Q3?!1AoU`c#}E+IJex z78_sqQR=DFo!`nBGx~wV{M@vFGX))!AW>u8R$$u`UDfKtIXj*Drss;7BpO%VFiHI0 zw>AK^pPKJOP45-GbM#)h7R&XdRvz#S4{8Op)_VEKI6v;YK<uf#qV6O^gE`|uHc1**2VQnQ zk@5j!kfn%H1wi5d1lq|vt-NR$PaR%VgQ0b{ zwqpMaD{!)6f4DOTIh$wOVxkvLd2Hng4W_0`6TQa3+P`e^*u>(3UuTRPbx~AYZ1D5u zE$>uqmp33nGX`l;B^3afqrIohJGQ3QnO(YUc@K>ed&Tge8tj#F$Tf;k4T~=uQkX$F z5SaC+?uK#gXTnp_6s%FAL*@x#EX{aF7sX95ZFSB}yu zu5;r>MhQ*t@gGN*IUE>vlkjRX6zMFiOUVpqW|{hf@d`@!*2@8DK*<`MAJWhu$63FA z3u@l}0HkOLugLYXO}<6$XnNmB#GF_kLoGB+f&4FQI;;wkO8?lxj z$4zVo57F};>^=)}A92qbHLS_eDj9U6fuua|yGTm|tK=H*v=AH#_c)C?hK2PMdW>mc zc?(sOVuNELCd(fo;)-*MO2Kd$!k2jE918ax{D2G;)nz2~abvXQ?_9XhZi z;IcQaiYE4n)m)_U@;t7w^7H* zL(DyWgpXvBW}so42+8{^^boR~3PVe-UNX5u)J-jav5OAE-^Q)yb=N>b4lv?YplBB0 zsBfrqr?TCSqaUxuk&o9x?g+Q{3JsDZf1|VW_$niNuec-;YhcMQ{5*F5(T1C{CXIbK zskksFXfV5D1M^mQ;sCJe5ui~cl0%(;9R4>iiInx+NkD9}y4P7B?)VO%xkBCZMth0? zei~S@eLRm$0r58pkxPuw`^ZqxpexVKhu${UAl&z|vAq-YzNM51;!khJJ?RDC(t-dQ@+}7#U(1I{(paGU6!h|{_6P#IYK-7#y|m*@C6ne2B4W(2XuA$gMqUF|--pLHr3 zDx~phg$j-FYawQiG#kTj5=loP61k%jHSd0e`gNNjcZQv6>Nq6aX76lVX>{)umq*R< z8KPy>rkkqA?j4rUH}`>zveN5fl9K{2d*g06{LnO40_%S(4p}XQuKJ|DKw`eg2w^CK zB$oaZc-3k=9830ifNB0}gq{S}wIe1eR6;KYGaRWa9z-;J6<}_lx2vxDgA9whmjB_L zI7gQMp@)v?`bHOK5E6go%udd|yW=U~a0s}Zg4GZAAU%p6+0|vB<%l4)CH5~^@m4Cw z(YDbHEPB%EHRj$AMCh?|gbGQ;;w=2`@FGdperf*UO~s1GdlO=yLnlXUzIyM?wIhm)ut$R8&L*U`Je8Ynp#x!aMpyf=|Ppf@wCol zYv234NM+Va=<+3NGuhGk--`D{0!|(jw^J<+4}Zr>*K__1AUe+Xn+#QuQM-OqXmCBe z#qltphla)|Q_uPT@t{3P&r&c|-5DCq5VREZpwM`8@E_6GrGeER;9=%llNvrD32)4- zW!=-aNzJh9X`o(bkhT^x;hOToku|1!1}oQtI3fNnXfSG3l8FV&3orD3S}e) z8m3{Xgb01`fH6^lnXJK(`ev5_!*2nyS%=Z(I5>TztFG$mz`SHy>;tO}p#gf>hkP9v zc(M5Yg-Gn}?Kt%MDjeUwEBvIQGMZ$_-->HYf1`By^0pAEAgFF4#=xq2{Jx7)hLrp+ zZRF5WTTo?hJm^#LUR42WAJneyTtY68J_Lx*7Fl1;t3jiM;g4|K9*Mu|dx7taIwf=P z1kkWmJDqsj&h%K(u%ZFPF*+YWJZx!@GK?3j5WkdEC;-63S#b>r;MbzcA-wf*!BMC}wh5yzP+>wr|M|e6tAyv)RhZ1fg3wB}f0F;1Nnqq14k8(6aZb6dr-`s=dB zk6xNmQru6oOhH!#@}pk)Cb0eQDpl*{G2YI}b;EEJ4{^GCT~~r2YNkrJhJo^cV`s4vOzuPv_26DJE#ia!kIs`r8iIM6nP+7n%w*1)Ry>wQJGwDj+%myNh1E{$o?iC(i-5r$)UFcby`aex`4d=ssr2o4k7Cy8Z*z*j~Oat2r z6{`CY1^E=iw+!8uTrS9WLnxhR&Z6SKFQMg7ZP-agB}gYF8FxhIrM^z%_3th zoGH@uu#q2%-mKVEVUP2GA-N$7&gvSz?8@rnL8AcKy=+x}?~kn)MSpb-Rcf@K^lqk4 zUtsDlL^#zU#PpE^>ySzgC$2qpPq4g0n9#s5;js-GVxRO@MgZ*-^Wq@jku1&(~7;$aVu&`=?8Rl!{OXofda0>|~ndZ?KVy>4_<()YNw-9YX{0lg`L7j%Ee)ew(j)K& zPwEOawE=n1)NKOV3|*EgG`}T=^Rmi-=?{1BkCy{_U>SP$C64f5-qfD^RUwtF1CD%V zrSALEV=(_t+?#^K%5;Ceavexf!LX&4*{w9J2V5e;Qtpym4t^j)g~Vl9p~7HR*z>z# z#9i6j+Hh#ayT+hpP&6dJXM_E=vL`;MHJkT}qc??tCCeX1S1fz+rrasxSoS7QS1`Nl zw&zWa97~`4IItfR4?G%I#4~vUXgjy86qMaA0L7uedjvKs{obMh$^-y<`<%Teo_cho z&Qo6&{z@cH6wL<4-rrqgWN#-kH?skK3Bk0yLGyrjCkz)UykjPzd+;@1BmO%t8LTY8 z?}qaw!;#HM9xxhL#6oIq=p^?8hFk{}UeJ@af>^%Y&jFPyw9D8vqW;4*CIxqOHBfR{ z$Z=Pka^uz=3hx#9ufi@ecw=4^o0s;I*|1j*-5K7%s(t2rS@w?jg&AW;{4hQzJ6Y4R zH)?heZ-@Ke2EKek&C@-fA!wEblbH#pM%(PKev2`}gMrOBxVMP)%9#L=_)(3%XaFBs zBS6UE#H$52Ywg~q2ZDS#JRqHg^OuKPgE%np@fz33q zl<<6%@Ep^FOtRaPhlD4Qq^nvB@uDoT}qcMz5$9D%4KNbam@jiT-^4v4SI-?hf54A&h2=07J@ENHI?~*AxcM6b@>AoL+d)rS4 z!&YxBo)L8%$}!QCMdDj#9W$eto~xirLa7`)sXhi?3JknVgehI+;QPStXSB&+R5_%G zevIEfUc`yJ${7>#sTvR1E|Wd?Hrams12fbd^t51xHLxm|EuNIzzwqJA31u^NDSM-K z3-gvp{;R`l)xL4=IbyCD9`uBxaBZ=pRe;;cHPjnflNEx~N$T}QPYSaw!&S4<{~e+K z8{`U`@_&J}LFf8ni6<6$u2OkPpck=VmUkv`?p0m{7@D;tGBrSAUwT8C%|-*yS?Fn} zfmQXUwivL;)THlO^(h2K+zJ#-R|h5W-J)Ml7!26XsP{iw+FQPR{*#}Xp*ERET^rKC zs$8~cUh43nEPFFrm$EnhY(1v8fAK5ecmM|pvw%p=;L0QAseh&13qh;B(0fIl5cfme zNlb#e6*^NN`MgZ(G;!`J9*Q#`?Ov~pfaIP31ZqB2*BU)0B;53tkfGF|tPx%;OCnPP z%o^@H6&QAdpqFtKCQK-y!u9Grqmikl;Ah3(8$f+(Uoy2V7|OtsWm&3v{N8Ib%Sx9f4;oM$(o8{58Y9->lOF;+%>5P84DiFG zCOk+l1M7+@AY=o?zx|!77SEH^l9_|Pirlgoi45$22iWsm7uepUa}4LO zdHF7$FRCuk`y2)_6tG>XIVk@wy2ZAn?BAbl>jpgEm5xlVsvxH1H*50&pW2RrGTF_8n9gkc0rPE8CRdW zMOwZ*{4A#dYgW8y2m`D9|NXEqDLLW08D%5xj>||-@Oi)nIcdLMXHCEl?+vVE4dd!e zb*Bs1lh6}zq5>chWN!@(I&{OjcVw^j#(hP7k?)GY_Otco&m81OmcVoxmNaY#Fz5fr z(6ql?XvDDbCOquM?z^q>4S|;-o=}abHLxtY1~u9=|1-W=#T#}C1OC`1D^#dq zg9Yv?ccSl0rP_A=c+P0Rc0jTN_@A>0ssDT4qs!0uF%`o;8g>J#;;;9PO3KdrW!Cu7 zmqsNdI0}FnM_~*Re)PS-NI&^uA`VO8vWas)C*>gB0i12@y`e#eW|$N}uOAP1PhPC{ z7E$0<@$Q&9JTHtX(s`n&q<2$N-Ay#2nk$KMP=_v}}}v^xJ_?81{xs0De! zjLwJ0%hcejyNp#Y(G6cZ3F6<425gss78~UIo6dIpd)8B{&jv9yL%kX{1M9$FzH@2v zupz%s8&)#Z5MXvs%RKGOKVtB#ulSBL4Oi4sAKsRcB6RSdaQhDF$Zz0U(EwLl_oh zk>>;Ns@E9zD9K*wQS>JCAhL`U3vF8x`5GYpitO&pcw@GztJH53MpoSx?Ts8>NRs-B zP`cvnrIFPo4t_9RN?4bXM65LaW&SZ(!VrI3{VxIrUFrMxrPGd*Wf{lG*uH{{?Z$`# z$TC*RvV6z*zrJ@!k|HO|D=Y@q#)Wg{54`@$zorfwWQQENu;+#ZI~J$txY67Me^B_D}nwC zx*PJGBY&sF`|W)p@Vc#@bd`6WFs^(RepfJ>%_19{fB2oXvwo@pA_R?N{{`}3wx znUXtWip>@mtINbRYxGP5@a12C>W?&Nl5XxUl^fv)ufdFTZGs_HTbu|7+FOnCF$i$V z62Ky^=_3TF-5Yg>lK4<5XeiWX5i;|TB!v@y*nNCQHv+r<4K(afKW>I$7{1K*!6W<@;#dx)TJs8$_OKkFwu8`SJG~ z3^E?gh7mFYYu%!Y^I|&Nua_m<1z<=_pQNbbYcE5e;zAgPlEIx?6>PzOfr?i(Q@Yhq zFVp}-94uh1<`zy5CrKR1l&)4{lYv233E-@=9Q**-{U1@gPPItF2<&@-_XCaNY$_L_ zOrwiZKzyjc@bJ(jmXD#NPzl3ZnPtM8!lVE~1k7q=(U|Wy3m9@Oz{1e3!Vn>iEQSoV zx=7ME&KTaa__Uh!V=@NU`_utpScf`n=)jhaxCO|Yq>dL+&Aj}4Mz-70uxXoOU>PMe z2%rX?w%hDd{YPdliQ{Q0LSkTTzH9DayG^=Nl5sO+ITw;ZD5eY^fTAldLQFCN&3^8d zP(4l;bH(cd$6|@4fj~6Ckeia|FvvRvg`;g6^~@}#A)r>6N!rf<4O@&~kB)Q68Y_q#=|Ltwhei(Ze4z+A6N8yEQS?s_%-JSU;>pbT zOX3G<(D$DYFzeJ=SnrbGOcoedOAX>{pED68Z%S7Y_y7(I#VcGT)}3`ULuOp1Bx-=SSK`UYhej`x zFX2IO>X4{O$$D>UB`FV>_+ub*Py4Ls^ zolKfwXg0RbxtX+`2I@Bn8VtP;TY9f(;5qkC0%ID{X6C-*UK@53kUI__zR+2?H|RN~ z2UV+#Uxuw&5IH(2@C!M44e4Vu1IhSlXSMWqWX>ZaD4kN$ejkjqfrks z_I5;de)Dv;eVy4$;&@tCT@9>Fch9{5vb-3wbQvVLHQl4);!ymxOOP^TpfN**JV+XM z0w4dtye|DP{iv;OA*c>`xYNi|^J`PWZhJ+BsXyVB&aH`ghJ4jf6tw^vo7r z2n@bPcxhaP_&*w1BqH@^FMB+#YyiuTDQii(h5$Am*PZn<34o`kO;6!(pI$!J7$ig> zOhSXIe*G5Iu38OyhcU7S0d&Zae<9lw9-Z*F6%ktkAdoHUbDO+y?X^)Q8O;|7 zGXS`drgU$DIIQApE=6pL8}1{Yy@lWbW^{e_KUTf15U4t$x^PfVWQ+o$ReESy^O84g zX0NIh_CtKptYzKb;J)4Q6i~fdZA;ysW4rVg#HS0cE*?(A5b^d;s*H})`g?x@8~M4n zIBtgLNIBv9wIepCZlfTr)xrR9H&%v(`cCf(ZMi(aufH3<=VE#T&Pp zUmCNXhznxqh=z<>QPRJs0h4~x{SA5!7$Q8jQEf}^pQBz#@~8+29Sw5}_B}7sVh~(T zBhghH*_wKKu^1wvf#)ea%#u&^r1=}d^*!^@J;AKF;Wvw{Q`hWRh6)LIKlHwKbymrP zMNd{jj_6O#Z_8O5Ow8b#>&2(X-y<`685&F-5W016(^Kc!R)z1XX~!NA5|BzWpLH6zgyGm`fOV?uU{MNx7zH|?J__nIwv+b?@P-}!lJ7dAiZ=rq$t&| zg=W8yi-@<~fV z?4L!G%_{T~_May_Sp@RC%8@TbCN?u;wel1)4P=c|Kb~HYYt`Bq>n+#*lUZDzjZvjV{N1Y+nqJww-Mw{eH-tdGsOn! z9$ChHLtwn!imDfNCwI zx?qBXH-b!s^K5tEp=hng9B6wC5t8dkA<}d?TBu_Z-d2C?{{_O^cz7XV7@nRpR(> zZ*LKF39Pplh|n{}8@4FjShGx}_tzcFcR>;f43=JP!r@kzbntsFa48yQr)!B0c>?Vel zoNP@M8Z)Z1Nhyt>K2s55iOGJ@xPaj?O!LT52 z*8YYDl`%;``XFHTpSzEcp_m;{0t^%OX33obkix>-cZ4298dzKdt&P#bIRNYTc@rgU z^+{KzoyK9SP_I2bNkgsy`d!$Q_lZyol8>?~Myn3qLPsHW8q~y7Duz~EnbifX=$ayP9P5R~!&Scgz|j;5N{YKCwLvNlgA(cde7ik{+zu&kVa7AsHBJ*!7`-<)gO- zop4xc3@i@q$XdbNuQxYSD3qQ%UX*Nd2l75~P=pG(F9W(zsGI;Z4T-Dd?~le6S@Q|= z&=S~Az4A@ckWDNPaX?ftXCQ>wRZK!Wv zDta>bK_(zJDCr{XBo2qn=t@};NpMN=Moq5?vlRms9v}lR1xmlwy@k51f}(+5*WN6| zKvD0$JmJkG9o?xt!?#)kix@DabWf}KSBoCv0T+wRRwjW4`NG;#t-GVrF~f|*?yEFa&m z=1ReT7L2iNq;;nEh{d2;6xum6mt*9fr-4-iJ2jWfQOgX zcnyCPV?FDK28g>#0kX#mFsvF;@K@`!W1wcA&V-$EyEd%KWYQl0eIRFS_gS&nE;9&e z#2HSyGB|nbXP7k5@Ti)3G0A{9I8QVQjy4$nCqI(brGIiJ`NsNj3=9vl|47OBglYtmTc&zfco>IPyY8g~O< z{7T!yR}aNmZ3+$Wa8(E&NBPEG@p*C+k$93BM@Ikn(^GK%Lja3CI}33xd!EydJzLAY zq=5ei0!jTuVe6Co_48y9Z^w`@nfbj5LDwvsL*h>@g^c6ed(L$T-L+588F5&8P(^4t zAAj27rH0|_ftPj9aCNjnFDtVO>AfRL$LPY$L;~6eUken@@V%!(G#}!wXk4AFIAAE; z6@WS!^1X4n>90mQV|zdb*4o7jQsP?MFO_Z5cL0oohM9u??!CeV7b0`~Xk*~9n4z`v zDWK{tf2X1U^8`}!hLuzxZdXh_XIY3yz;*4mly3pnk2}mme zW3)=y)2 zFj#z)AHxjjQLcI3L}2PKy1z~@%#MEo2i^^+SzTXZSWq!K2A}Ju?UcYD5%90ICxZmC z#9<|5d7qYE9xNJo^kUJN^d^yNV9_w?I~5pqWA`<8=;BnZ@U*fZxlw;_#P5+WkAQY& z?D`5f>-qya*SLba+Pob#E8jO7?ut1jJ31wK;mKaY*zT8sRRAhM)xN%XLENbh``xl^ zXZ2X7fvCo6>AAQ16c?iS>Prxtmf|}rNY8<=?N)lRo(3x4)c#QLckFb%^Fy12AB7@YP|ZLc&t!}#Mc;WBgr6Ua zUaYz=f%Ok-pLwKKAr4|amWp5)jE9NqiqgO$$Is~+wXH_hbJPpjw0&ifan|-ufxY5E zZ`9kg^Xl-h8gZ+@xHwDQmM)5hZN^$lg_N-$K;XBl7n=HRVl74u3j#Z4pFUh%Ks?nW zCw;$q0&Te%$4M6gs+q+}7g?mS10zT63dW!+UsC$i^xfP0sW>qZbl zEV4>P5o=~2dt1K{kGG@c3=X{f7EbP~G8*oRn)o-O@#C?7diSuTxl204iVm_nk9Vpq zcU(L~j_P<^hI~OdfbHJql|TD@WKS87sQB=fBv4YinN3*vdgyNu{78}HE@Px%CU-Cv zyDE;^Q4L>e58e%OQIJ?kpeKf~B{8?+C*JHmwYp1J$tkx89KH39c}5Pgz|i`k5xfc8q2h%KTdlhKnZ z0^LtEZj0uMg3x{Xx^LykdQsY`VW+;CrM~9CZz(;FeWw8>mkF8=1BtzjxT{Z5w{ElH za95DAMT(N{Y07R}*BgpC``Q*>Lw}p@p1nYlZI8;32$%>n@af!CqT=IGbj3wT9aaJ< zN^=rYyJ^1`*gI#bdP8JqG3;d|;aYIdvUH6*VR8XISS)9vB^HYZCNuen{c^@a zF*Hd!4idheI;fx5l2|!{`WdEl_N20ZQdG1Y72c~zp=j{5=SYz<^y@&;9M9fF66EfC z6{y=B9(@pE!HX+vDw4yC7c>J2aaWC7cA)yL_l$?T0*=bE?T5*+w&w>wwlV@3bAw-a zuLjl&*N%uS$?W@63DOUY7Aj24&qeVymx6T*eX=wMuP4tf5FESb8SzmF1uqtjsjmn# ziAD1=Ii-61eo<#F6l2p<&w;j0%mmBSWRCKjDo+mv0oFX^Op|TN48noH%*T4pi^dg! z!$u2p^03Mp>lqJ6gM);h+^<@%0}oCTy~bw?91TNpq(tD~EcUE;j&!67phtv89=*-{ z(b7}KP*_`&@SJfBdiEda??>zRSW<@ESl+xsCk_DnUIJ=9>+)vmxGv7~CA?V7KGRzm=Af~_5){75f6yz_yjOs>d$W*9nm8QR zq>FY5E7Q2*0Y}dXQ}xXvG!j_z?Yv)hA2AJu?N0*xUN)Xl%{|M61I5VjAPl?LZxx_- zt%YHAdXVVRqJhKTZYVDv?4Ns)f3qeYjmS{;ueCk{X^-K-VK)o!kT+Z;*PjVQ)gK9X z1J_C~p@)$Lx%-|647fxP!x~V?cXja9w{fDp(ulaLb+RNa8dsmXMOwbxSbPy-TuW8i zft&7{Hv^JPBWr{ng`I<$f9|wN$el3-Q3+w>C7~B<@AE+UOZt8=8QvgiBAKZ@VXmB& zsQ}!!39mq}7BYt?id1Wcr+C2gQp^L6##M8_P=es z6=&_X+$rAcKr)MrV0W!b6d6woy?aD7s<>}Sd61OvT^HO7wVwb7-UEmyfun;F`K*wm38nPYm-o4{>y3k|xedru6nkOa3T*dopCkm*khNdIjX;UY2)2$%%gN(P9c(5Yc0A?3la=~3|k&{C8# z4gH1pN-Y-)aSOz=e(Z zEQ~{j{FrH-l-uHLQ8w}%328VyS@ejoI{cl`0UAVIej8XE z_ttx6kL&Ctb%Qh!K$wu_o;6r7ehYE=qP|Ay_h{`G@NA`+8THQ7c zvRSQRbZLMYktAyzySTebh?8Lr!oAD2#ms1>c=AxO@G@)Dc@t)jeT5&?s&lIy^%{^w zc^_xG0!P;Ep|`cG7ubKkFtU7Q6RID0L_FEq+KM9|twG(IjmFCu6dK+Q$-da$+4PYW z8uY&90y41J_g;ApQ$g~a>GTVjxLB6sF zl?<#J;k~i|!dkDYaoS^QIT^88cEnj2THEoDt^(x78SYmjVW^uWV?32gaXiQn4?QI; z@nlKpH9!yPfGc`td(y}vubz@Xp+VwI)+k`aH-PN2(9hAJJ=)tl(6DhUYFB*(yYVsx zskLSq(vsGMlTV!Y=$bPIRij~s6|jM|`Tm({_OsEy2Bh01z;NUtF@2IS;Okc+v9K>B zTfox{e4(@q6*@8qi6!tPj#_R!ln4^m;sY4??5#KT)BrP|#@s7vr8x_YYkIJ%SL@k( z;BC|M#&R{}9r7lMfwfOy2rUV{2AH8*IJ;-R{Kn8rdT^ySWo)>QM}8A1o)`K#8n8#% zZpVo|6*&0XJLqUJCag(@^xsY!elqd#Rn?MY9WuVQQBao0)`jy*JE0Je@=I^HP$A3d z^uO+M#AT%UW{(V%q}t5%wElr3UiK5t1VR)|n5jR(+<1f&lIvOIW|Xk@WoCo`0T6@J%f zU=6ue9dUB7{TclIGl!4jz^iZL%#mY;%NV5UBuMLI*>-<(-r4n5A!l`)DJTPrU2I%5 z=W3}_`n@Dc#WG~W6oht6KXqsc3NM|D*p%eZ8(CV03VApw1)fLrEH%Q=5JADLr>7-f zjk-N#Jr!yVC>ex*6zufQ!VFeYG?4VxsG_jBPx7ACMSwmp3#_AQNr*Kdi9`ff`VYq_ z99XOaZ)j7#h8Qe{yUjqGpyNu2GB_)7qP)s@8G~Zp`(>N_y|_Ayt=*q(5VV1{;m*qv zCEMAbO8^nKVM^WeKINGrkSz(Z1|*Y9?V8|9JSdypCT{;R^vKz|*o@Brvf)Z7xZjCN!P`W^pv+Jg4MrLb z#EzZVFN)w=;#mV+`+l>5argIpru=1K&ocmdfs86#YkFcCf^z02a^QPdwur=*1XI)4 zvLwVBkbwS|c!nZyGzu?P6>w}_@M9~v92k0|D7M@SrSohnj(+w9j(xTsa)*XQuA1sn zeksNt^P|%INmUjlgMW(E#K2;g8}Ghwx+L2kk%6&BV|jO|r09zINFO~i^fe2~E=in{EfaFD0E@KCN0PICxMFB%rR?vvgn0n850^)WZ>o;EU#5~ z*N+C)z^lC%Gj-heucGRr=z^F9_87`@YEdTIGZ1l?)Ken
    This project on Github: thejoshwolfe/snakefall version ???
    -
    Check out some community made levels, and share your levels there!
    - +
    This game is a clone of Snakebird by Noumenon Games.
    - + From b21361970b45a7fa756ff5a1653295ddf0477bb0 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 16:06:14 -0500 Subject: [PATCH 217/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index 8f7b9a4b..22f72da7 100644 --- a/Framework.html +++ b/Framework.html @@ -87,6 +87,6 @@
    This game is a clone of Snakebird by Noumenon Games.
    - + From ede9e619a008c43275448d5d29beeb9cd685727b Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 16:07:41 -0500 Subject: [PATCH 218/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index 22f72da7..9555c018 100644 --- a/Framework.html +++ b/Framework.html @@ -1,7 +1,7 @@ Snakefall Redesign - + From c27f960b6174d07d5e6c201460787fe5daf12e25 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 16:12:04 -0500 Subject: [PATCH 219/577] Update Format.css --- Format.css | 1 + 1 file changed, 1 insertion(+) diff --git a/Format.css b/Format.css index 7afd11f0..cce1a992 100644 --- a/Format.css +++ b/Format.css @@ -146,6 +146,7 @@ td a{ margin-left: 25%; margin-right: 25%; position: relative; + padding-bottom: 1px; } #showButton{ From a4e790736b5310a2810943e676840308b38304b8 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 16:12:46 -0500 Subject: [PATCH 220/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 6b597c0e..45311c8e 100644 --- a/index.html +++ b/index.html @@ -26,7 +26,7 @@ Original Snakefall Github
    Show Hidden Options
    Most checkmarks contain links to solutions, though some are not accessible without a password.
    -
    +
    Standard Puzzles
    From a7616d79f35b02580ec5979041813173c9fa484c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 00:48:22 -0500 Subject: [PATCH 221/577] Update Main.js --- Main.js | 124 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 88 insertions(+), 36 deletions(-) diff --git a/Main.js b/Main.js index e3555bcf..8c5e7fbc 100644 --- a/Main.js +++ b/Main.js @@ -473,7 +473,7 @@ document.addEventListener("keydown", function(event) { if (persistentState.showEditor && modifierMask === CTRL) { redo(uneditStuff); break; } return; case "R".charCodeAt(0): - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } if (modifierMask === 0) { reset(unmoveStuff); break; } if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLR); break; } @@ -484,10 +484,12 @@ document.addEventListener("keydown", function(event) { case "A".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(0, -1); break; } if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PORTAL); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } if ( persistentState.showEditor && modifierMask === CTRL) { selectAll(); break; } return; case "E".charCodeAt(0): if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(EXIT); break; } return; case 46: // delete if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } @@ -500,24 +502,22 @@ document.addEventListener("keydown", function(event) { case "S".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPIKE); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(SNAKE); break; } if ( persistentState.showEditor && modifierMask === CTRL) { saveLevel(); break; } if (!persistentState.showEditor && modifierMask === CTRL) { saveReplay(); break; } if (modifierMask === (CTRL|SHIFT)) { saveReplay(); break; } return; case "X".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(EXIT); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(OPENGATE); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(CLOSEDGATE); break; } if ( persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } return; case "F".charCodeAt(0): if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } - return; - case "K".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(FOAM); break; } return; case "D".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SNAKE); break; } if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLD); break; } return; case "B".charCodeAt(0): @@ -535,15 +535,12 @@ document.addEventListener("keydown", function(event) { if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLL); break; } return; - case "M".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FOAM); break; } - return; case "G".charCodeAt(0): if (modifierMask === 0) { toggleGrid(); break; } if ( persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } return; case "C".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } if ( persistentState.showEditor && modifierMask === SHIFT) { toggleCollision(); break; } if ( persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } return; @@ -942,15 +939,18 @@ function paintBrushTileCodeChanged() { var id = pair[0]; var tileCode = pair[1]; var backgroundStyle = ""; + var textColor = ""; if (tileCode === paintBrushTileCode) { if (tileCode === SNAKE) { // show the color of the active snake in the color of the button backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; } else { - backgroundStyle = "#fdc122"; + backgroundStyle = "linear-gradient(#4b91ff, #055ce4)"; + textColor = "white"; } } document.getElementById(id).style.background = backgroundStyle; + document.getElementById(id).style.color = textColor; }); var isSelectionMode = paintBrushTileCode === "select"; @@ -2589,7 +2589,7 @@ function render() { if (activePortalLocations.indexOf(location) !== -1) drawCircle(r, c, 0.3, "#666"); break; case PLATFORM: - drawPlatform(r, c); + drawPlatform(r, c, getAdjacentTiles()); break; case WOODPLATFORM: drawOneWayWall("#D38345", r, c, -1, 0); @@ -2637,7 +2637,6 @@ function render() { } function drawObject(object) { - context.save(); switch (object.type) { case SNAKE: var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); @@ -2766,21 +2765,74 @@ function render() { drawCloud(context, c*tileSize, r*tileSize); break; default: throw unreachable(); - context.restore(); } } -function drawPlatform(r, c) { - context.fillStyle = "slategray"; - context.beginPath(); - context.moveTo(c * tileSize, r * tileSize); - context.lineTo((c + 1) * tileSize, r * tileSize); - context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); +function drawPlatform(r, c, adjacentTiles) { + drawPlatform2(r, c, isPlatform); + + function isPlatform(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === PLATFORM; + } + + /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*1, r*tileSize); + context.lineTo(c*tileSize, r*tileSize); + context.closePath(); + context.rect(c*tileSize, r*tileSize+tileSize*.2857, tileSize, tileSize*.1429);*/ + + /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.25, r*tileSize+tileSize*.2, c*tileSize+tileSize*.25, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.75, r*tileSize+tileSize*.2, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.lineTo((c+1)*tileSize, r*tileSize); + context.lineTo(c*tileSize, r*tileSize);*/ + + /*context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); context.arc((c + 3/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); context.arc((c + 1/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); context.lineTo(c*tileSize, r*tileSize); - context.fill(); - } + context.lineTo(c*tileSize+tileSize, r*tileSize);*/ + + //context.closePath(); + //context.fillStyle = "#000066"; + //ontext.fill(); + //context.stroke(); +} + +function drawPlatform2(r, c, isOccupied){ + + var x1 = .05 + var x2 = .05; + if(isOccupied(-1,0)) x1 = 0; + if(isOccupied(1,0)) x2 = 0; + + var platformColors = ["#ffcccc", "#ffe0cc", "#ffffcc", "#e6ffe6", "#e6e6ff"]; + for(var i = 0; i<5; i++){ + var j = i-1; + if(j<0) j = 0; + context.beginPath(); + context.moveTo(c*tileSize+tileSize*(i*x1), r*tileSize+tileSize*(.15 * i - (j * .03))); + context.strokeStyle = platformColors[i]; + context.lineWidth = tileSize*(.15-(i*.03)); + context.lineTo(c*tileSize+tileSize*(1-(i*x2)), r*tileSize+tileSize*(.15 * i - (j * .03))); + context.stroke(); + } +} + function drawOneWayWall(fillStyle, r, c, dr, dc) { context.fillStyle = fillStyle; if (dr == -1) @@ -2842,11 +2894,11 @@ function drawPlatform(r, c) { } function drawFoam(r, c) { - context.fillStyle = "white"; - for (var i = 0; i < 3; i++) { - for (var j = 0; j < 3; j++) { + context.fillStyle = "#ffccff"; + for (var i = 0; i < 4; i++) { + for (var j = 0; j < 4; j++) { context.beginPath(); - context.arc(c*tileSize + (i*2+1)*tileSize/6, r*tileSize + (j*2+1)*tileSize/6, tileSize/6, 0, 2*Math.PI); + context.arc(c*tileSize + (i*2+1)*tileSize/8, r*tileSize + (j*2+1)*tileSize/8, tileSize/8, 0, 2*Math.PI); context.fill(); } } @@ -2855,27 +2907,27 @@ function drawPlatform(r, c) { function drawGate(r, c, isClosed) { if (isClosed) { - context.lineWidth = 3; - context.strokeStyle = "#444"; + context.lineWidth = 2; + context.strokeStyle = "#555"; context.beginPath(); - for (var i = 1; i < 3; i++) { + for (var i = 1; i < 6; i++) { context.beginPath(); - context.moveTo(c*tileSize + i*tileSize/3, r*tileSize); - context.lineTo(c*tileSize + i*tileSize/3, (r+1)*tileSize); + context.moveTo(c*tileSize + i*tileSize/6, r*tileSize); + context.lineTo(c*tileSize + i*tileSize/6, (r+1)*tileSize); context.stroke(); } - for (var i = 1; i < 4; i++) { + for (var i = 1; i < 6; i++) { context.beginPath(); - context.moveTo(c*tileSize, r*tileSize + i*tileSize/4 + tileSize/15); - context.lineTo((c+1)*tileSize, r*tileSize + i*tileSize/4 + tileSize/15); + context.moveTo(c*tileSize, r*tileSize + i*tileSize/6 + tileSize/15); + context.lineTo((c+1)*tileSize, r*tileSize + i*tileSize/6 + tileSize/15); context.stroke(); } context.lineWidth = 0; } - context.fillStyle = "#777"; + context.fillStyle = "#111"; context.beginPath(); context.moveTo(c*tileSize, r*tileSize); context.lineTo((c+1)*tileSize, r*tileSize); From 13f2e2375f59163fbd5bdd6445a6a593a4b65a37 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 00:48:36 -0500 Subject: [PATCH 222/577] Update Editor.css --- Editor.css | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/Editor.css b/Editor.css index b5075be9..fc015014 100644 --- a/Editor.css +++ b/Editor.css @@ -1,11 +1,11 @@ @keyframes click_me { 0% { background-color: buttonface; } - 50% { background-color: yellow; } + 50% { background-color: #ffff00; } 100% { background-color: buttonface; } } button.click-me { - animation: click_me 1s 2 alternate; + animation: click_me 1s linear infinite alternate; font-weight: bold; } @@ -13,9 +13,8 @@ td{ text-align: center; } -button.click-me { - animation: click_me 1s 2 alternate; - font-weight: bold; +tr{ + text-align: center; } body{ @@ -24,6 +23,16 @@ body{ } button{ + background-image: linear-gradient(white, #f2f2f2); + border: .4px solid black; + border-radius: 3px; + margin: 1px; + box-shadow: .5px .5px 1px black; +} + +button:focus{ + background-image: linear-gradient(#4b91ff, #055ce4); + color: white; } #levelTable{ @@ -73,3 +82,11 @@ table{ .header{ font-style: italic; } + +#selectHolder{ + display: inline-block; +} + +#controlsRow button{ + vertical-align: top; +} From 6c5ccf6c6848c7ebfc6a1dac3d2e15a1b3b3ba60 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 00:48:54 -0500 Subject: [PATCH 223/577] Update Framework.html --- Framework.html | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Framework.html b/Framework.html index 9555c018..6c16a150 100644 --- a/Framework.html +++ b/Framework.html @@ -1,7 +1,7 @@ Snakefall Redesign - + @@ -20,9 +20,7 @@ - - - + From f8a27a7f28200ca6991b3e84305c69400dc8338c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 00:49:08 -0500 Subject: [PATCH 224/577] Update Format.css From c2199dfdd49858c444150c44af5b0fc857ce6077 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 00:49:27 -0500 Subject: [PATCH 225/577] Update index.html From 4539df2146a4e09676c3181eda4d6eed938785a7 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 00:52:25 -0500 Subject: [PATCH 226/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index 6c16a150..c92ba5ed 100644 --- a/Framework.html +++ b/Framework.html @@ -1,7 +1,7 @@ Snakefall Redesign - + From dfa8d11772f627853bb9d600ef7344af249419f4 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 12:22:21 -0500 Subject: [PATCH 227/577] Update Framework.html --- Framework.html | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/Framework.html b/Framework.html index c92ba5ed..902f5be1 100644 --- a/Framework.html +++ b/Framework.html @@ -20,7 +20,7 @@ - + @@ -30,35 +30,35 @@ - + - + - + - - + + - - - + +
    Controls
    Physics
    Controls
    Physics
    Standard Elements
    Stationaries
    Moveables
    Experimental Elements
    Removeables
    Gates
    Glass Ledges
    Platforms
    -
    +
    +
    STANDARD LEVEL: does not contain experimental elements
    Controls (hover for hotkeys):
    Arrows/WASD to move From be6e9c879d3a9ff8ecb7fcc66cccc5c9fea6361c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 12:22:31 -0500 Subject: [PATCH 228/577] Update Main.js --- Main.js | 206 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 136 insertions(+), 70 deletions(-) diff --git a/Main.js b/Main.js index 8c5e7fbc..dbb50629 100644 --- a/Main.js +++ b/Main.js @@ -30,9 +30,9 @@ var ONEWAYWALLD = "d".charCodeAt(0); var ONEWAYWALLL = "l".charCodeAt(0); var ONEWAYWALLR = "r".charCodeAt(0); var FOAM = "f".charCodeAt(0); -var OPENGATE = "o".charCodeAt(0); -var CLOSEDGATE = "c".charCodeAt(0); -var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, OPENGATE, CLOSEDGATE, FOAM]; +var BROKENGLASS = "o".charCodeAt(0); +var FIXEDGLASS = "c".charCodeAt(0); +var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, BROKENGLASS, FIXEDGLASS, FOAM]; // object types var SNAKE = "s"; @@ -122,6 +122,7 @@ function parseLevel(string) { if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); var upconvertedObjects = []; var fruitCount = 0; + var tileCounter = 0; for (var i = 0; i < mapData.length; i++) { var tileCode = mapData[i].charCodeAt(0); if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { @@ -134,9 +135,13 @@ function parseLevel(string) { }); tileCode = SPACE; } + if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === BROKENGLASS || tileCode === FIXEDGLASS || tileCode === FOAM || tileCode === CLOUD) tileCounter++; if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); level.map.push(tileCode); } + + if(tileCounter>0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL: contains experimental elements"; + else document.getElementById("levelType").innerHTML = "STANDARD LEVEL: does not contain experimental elements"; // objects skipWhitespace(); @@ -508,8 +513,8 @@ document.addEventListener("keydown", function(event) { if (modifierMask === (CTRL|SHIFT)) { saveReplay(); break; } return; case "X".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(OPENGATE); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(CLOSEDGATE); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BROKENGLASS); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(FIXEDGLASS); break; } if ( persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } return; case "F".charCodeAt(0): @@ -684,8 +689,8 @@ var paintButtonIdAndTileCodes = [ ["paintOneWayWallDButton", ONEWAYWALLD], ["paintOneWayWallLButton", ONEWAYWALLL], ["paintOneWayWallRButton", ONEWAYWALLR], - ["paintOpenGateButton", OPENGATE], - ["paintClosedGateButton", CLOSEDGATE], + ["paintBrokenGlassButton", BROKENGLASS], + ["paintFixedGlassButton", FIXEDGLASS], ["paintFoamButton", FOAM], ["paintSnakeButton", SNAKE], ["paintBlockButton", BLOCK], @@ -1551,8 +1556,8 @@ function describe(arg1, arg2) { case ONEWAYWALLD: return "A One Way Wall (facing D)"; case ONEWAYWALLL: return "A One Way Wall (facing L)"; case ONEWAYWALLR: return "A One Way Wall (facing R)"; - case OPENGATE: return "An Open Gate"; - case CLOSEDGATE: return "A Closed Gate"; + case BROKENGLASS: return "Broken Glass"; + case FIXEDGLASS: return "Fixed Glass"; case FOAM: return "Foam"; default: throw unreachable(); } @@ -1957,7 +1962,7 @@ function closeGates(oldOccupiedOpenGates, changeLog) var newOccupiedOpenGates = getOccupiedOpenGateLocations(); var nowUnoccupiedOpenGates = getSetSubtract(oldOccupiedOpenGates, newOccupiedOpenGates); for (var i = 0; i < nowUnoccupiedOpenGates.length; i++) { - paintTileAtLocation(nowUnoccupiedOpenGates[i], CLOSEDGATE, changeLog); + paintTileAtLocation(nowUnoccupiedOpenGates[i], FIXEDGLASS, changeLog); } return newOccupiedOpenGates; } @@ -2126,7 +2131,7 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { switch (tileCode) { - case SPACE: case EXIT: case PORTAL: case OPENGATE: return true; + case SPACE: case EXIT: case PORTAL: case BROKENGLASS: return true; case WOODPLATFORM: case FOAM: return pusher != null; case PLATFORM: return dr != 1; case ONEWAYWALLU: return dr != 1; @@ -2227,7 +2232,7 @@ function getOccupiedOpenGateLocations() { var result = []; for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === OPENGATE) { + if (level.map[i] === BROKENGLASS) { if (findObjectAtLocation(i)) result.push(i); } @@ -2606,11 +2611,11 @@ function render() { case ONEWAYWALLR: drawOneWayWall("#BACFD1", r, c, 0, 1); break; - case OPENGATE: - drawGate(r, c, false); + case BROKENGLASS: + drawGlass(r, c, false); break; - case CLOSEDGATE: - drawGate(r, c, true); + case FIXEDGLASS: + drawGlass(r, c, true); break; case FOAM: drawFoam(r, c); @@ -2769,7 +2774,7 @@ function render() { } function drawPlatform(r, c, adjacentTiles) { - drawPlatform2(r, c, isPlatform); + newPlatform(r, c, isPlatform); function isPlatform(dc, dr) { var tileCode = adjacentTiles[1 + dr][1 + dc]; @@ -2813,9 +2818,9 @@ function drawPlatform(r, c, adjacentTiles) { //context.stroke(); } -function drawPlatform2(r, c, isOccupied){ +function newPlatform(r, c, isOccupied){ - var x1 = .05 + var x1 = .05; var x2 = .05; if(isOccupied(-1,0)) x1 = 0; if(isOccupied(1,0)) x2 = 0; @@ -2825,10 +2830,10 @@ function drawPlatform2(r, c, isOccupied){ var j = i-1; if(j<0) j = 0; context.beginPath(); - context.moveTo(c*tileSize+tileSize*(i*x1), r*tileSize+tileSize*(.15 * i - (j * .03))); + context.moveTo(c*tileSize+tileSize*(i*x1), r*tileSize+tileSize*(.05 + (.1 * i) - (j * .02))); context.strokeStyle = platformColors[i]; - context.lineWidth = tileSize*(.15-(i*.03)); - context.lineTo(c*tileSize+tileSize*(1-(i*x2)), r*tileSize+tileSize*(.15 * i - (j * .03))); + context.lineWidth = tileSize*(.1-(i*.02)); + context.lineTo(c*tileSize+tileSize*(1-(i*x2)), r*tileSize+tileSize*(.05 + (.1 * i) - (j * .02))); context.stroke(); } } @@ -2904,41 +2909,105 @@ function drawPlatform2(r, c, isOccupied){ } } - function drawGate(r, c, isClosed) { - if (isClosed) - { - context.lineWidth = 2; - context.strokeStyle = "#555"; - context.beginPath(); - for (var i = 1; i < 6; i++) { + function drawGlass(r, c, isFixed) { + if(isFixed){ + var grd = context.createLinearGradient(c*tileSize, r*tileSize, (c+1)*tileSize, (r+1)*tileSize); + grd.addColorStop(0, "rgba(255,255,255,.4)"); + grd.addColorStop(.1, "rgba(255,255,255,.5)"); + grd.addColorStop(.2, "rgba(255,255,255,.3)"); + grd.addColorStop(.3, "rgba(255,255,255,.4)"); + grd.addColorStop(.4, "rgba(255,255,255,.6)"); + grd.addColorStop(.5, "rgba(255,255,255,.5)"); + grd.addColorStop(.6, "rgba(255,255,255,.3)"); + grd.addColorStop(.7, "rgba(255,255,255,.4)"); + grd.addColorStop(.8, "rgba(255,255,255,.5)"); + grd.addColorStop(.9, "rgba(255,255,255,.6)"); + grd.addColorStop(1, "rgba(255,255,255,.5)"); + + context.fillStyle = grd; + roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); + } + else{ + context.fillStyle = "rgba(255,255,255,.5)"; context.beginPath(); - context.moveTo(c*tileSize + i*tileSize/6, r*tileSize); - context.lineTo(c*tileSize + i*tileSize/6, (r+1)*tileSize); - context.stroke(); - } - - for (var i = 1; i < 6; i++) { + context.moveTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.1); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize, r*tileSize); + context.closePath(); + context.fill(); + context.beginPath(); - context.moveTo(c*tileSize, r*tileSize + i*tileSize/6 + tileSize/15); - context.lineTo((c+1)*tileSize, r*tileSize + i*tileSize/6 + tileSize/15); - context.stroke(); - } - - context.lineWidth = 0; + context.moveTo(c*tileSize, r*tileSize+tileSize*.4); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.4); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize, r*tileSize+tileSize*.4); + context.closePath(); + context.fill(); + + context.beginPath(); + context.moveTo(c*tileSize, r*tileSize+tileSize*1); + context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.7); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.7); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*1); + context.lineTo(c*tileSize, r*tileSize+tileSize*1); + context.closePath(); + context.fill(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize, r*tileSize+tileSize*1); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*1); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.7); + context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.7); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.65); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.4); + context.lineTo(c*tileSize+tileSize, r*tileSize+tileSize*.5); + context.closePath(); + context.fill(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize, r*tileSize+tileSize*.4); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.4); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*0); + context.lineTo(c*tileSize+tileSize, r*tileSize+tileSize*0); + context.lineTo(c*tileSize+tileSize, r*tileSize+tileSize*.4); + context.closePath(); + context.fill(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.15); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.05); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.15); + context.closePath(); + context.fill(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.4); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.55); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*.55, r*tileSize+tileSize*.55); + context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*.65, r*tileSize+tileSize*.55); + context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.4); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.4); + context.closePath(); + context.fill(); } - - context.fillStyle = "#111"; - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize); - context.lineTo((c+1)*tileSize, r*tileSize); - context.lineTo((c+1)*tileSize, (r+1)*tileSize); - context.lineTo(c*tileSize + 5*tileSize/6, (r+1)*tileSize); - context.lineTo(c*tileSize + 5*tileSize/6, r*tileSize + tileSize/2); - context.arc(c*tileSize + tileSize/2, r*tileSize + tileSize/2, tileSize/3, 0, Math.PI, true); - context.lineTo(c*tileSize + 1*tileSize/6, (r+1)*tileSize); - context.lineTo(c*tileSize, (r+1)*tileSize); - context.lineTo(c*tileSize, r*tileSize); - context.fill(); } function drawWall(r, c, adjacentTiles) { //GOOBY @@ -3440,28 +3509,25 @@ function drawPlatform2(r, c, isOccupied){ c.beginPath(); c.moveTo(x+tileSize*0, y+tileSize*0); - c.bezierCurveTo(x+tileSize*0, y-tileSize*.15, x+tileSize*.25, y-tileSize*.15, x+tileSize*.25, y+tileSize*0); - c.bezierCurveTo(x+tileSize*.25, y-tileSize*.15, x+tileSize*.5, y-tileSize*.15, x+tileSize*.5, y+tileSize*0); - c.bezierCurveTo(x+tileSize*.5, y-tileSize*.15, x+tileSize*.75, y-tileSize*.15, x+tileSize*.75, y+tileSize*0); - c.bezierCurveTo(x+tileSize*.75, y-tileSize*.15, x+tileSize*1, y-tileSize*.15, x+tileSize*1, y+tileSize*0); + c.bezierCurveTo(x+tileSize*0, y-tileSize*.15, x+tileSize*.33, y-tileSize*.15, x+tileSize*.33, y+tileSize*0); + c.bezierCurveTo(x+tileSize*.33, y-tileSize*.15, x+tileSize*.67, y-tileSize*.15, x+tileSize*.67, y+tileSize*0); + c.bezierCurveTo(x+tileSize*.67, y-tileSize*.15, x+tileSize*1, y-tileSize*.15, x+tileSize*1, y+tileSize*0); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*0, x+tileSize*1.15, y+tileSize*.25, x+tileSize*1, y+tileSize*.25); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.25, x+tileSize*1.15, y+tileSize*.5, x+tileSize*1, y+tileSize*.5); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.5, x+tileSize*1.15, y+tileSize*.75, x+tileSize*1, y+tileSize*.75); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.75, x+tileSize*1.15, y+tileSize*1, x+tileSize*1, y+tileSize*1); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*0, x+tileSize*1.15, y+tileSize*.33, x+tileSize*1, y+tileSize*.33); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.33, x+tileSize*1.15, y+tileSize*.67, x+tileSize*1, y+tileSize*.67); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.67, x+tileSize*1.15, y+tileSize*1, x+tileSize*1, y+tileSize*1); - c.bezierCurveTo(x+tileSize*1, y+tileSize*1.15, x+tileSize*.75, y+tileSize*1.15, x+tileSize*.75, y+tileSize*1); - c.bezierCurveTo(x+tileSize*.75, y+tileSize*1.15, x+tileSize*.5, y+tileSize*1.15, x+tileSize*.5, y+tileSize*1); - c.bezierCurveTo(x+tileSize*.5, y+tileSize*1.15, x+tileSize*.25, y+tileSize*1.15, x+tileSize*.25, y+tileSize*1); - c.bezierCurveTo(x+tileSize*.25, y+tileSize*1.15, x+tileSize*0, y+tileSize*1.15, x+tileSize*0, y+tileSize*1); + c.bezierCurveTo(x+tileSize*1, y+tileSize*1.15, x+tileSize*.67, y+tileSize*1.15, x+tileSize*.67, y+tileSize*1); + c.bezierCurveTo(x+tileSize*.67, y+tileSize*1.15, x+tileSize*.33, y+tileSize*1.15, x+tileSize*.33, y+tileSize*1); + c.bezierCurveTo(x+tileSize*.33, y+tileSize*1.15, x+tileSize*0, y+tileSize*1.15, x+tileSize*0, y+tileSize*1); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*1, x-tileSize*.15, y+tileSize*.75, x+tileSize*0, y+tileSize*.75); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*.75, x-tileSize*.15, y+tileSize*.5, x+tileSize*0, y+tileSize*.5); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*.5, x-tileSize*.15, y+tileSize*.25, x+tileSize*0, y+tileSize*.25); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*.25, x-tileSize*.15, y+tileSize*0, x+tileSize*0, y+tileSize*0); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*1, x-tileSize*.15, y+tileSize*.67, x+tileSize*0, y+tileSize*.67); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*.67, x-tileSize*.15, y+tileSize*.33, x+tileSize*0, y+tileSize*.33); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*.33, x-tileSize*.15, y+tileSize*0, x+tileSize*0, y+tileSize*0); c.closePath(); c.fill(); + //c.stroke(); } function roundRect(ctx, x, y, width, height, radius, fill, stroke) { //Gooby From 8f3ee720eb5e4905d08c63633560ae766289c52e Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 12:27:44 -0500 Subject: [PATCH 229/577] Update Main.js --- Main.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/Main.js b/Main.js index dbb50629..871e2ba1 100644 --- a/Main.js +++ b/Main.js @@ -135,13 +135,10 @@ function parseLevel(string) { }); tileCode = SPACE; } - if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === BROKENGLASS || tileCode === FIXEDGLASS || tileCode === FOAM || tileCode === CLOUD) tileCounter++; + if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === BROKENGLASS || tileCode === FIXEDGLASS || tileCode === FOAM) tileCounter++; if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); level.map.push(tileCode); } - - if(tileCounter>0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL: contains experimental elements"; - else document.getElementById("levelType").innerHTML = "STANDARD LEVEL: does not contain experimental elements"; // objects skipWhitespace(); @@ -154,12 +151,13 @@ function parseLevel(string) { }; // type + var cloudCounter = 0; object.type = string[cursor]; var locationsLimit; if (object.type === SNAKE) locationsLimit = -1; else if (object.type === BLOCK) locationsLimit = -1; else if (object.type === FRUIT) locationsLimit = 1; - else if (object.type === CLOUD) locationsLimit = -1; + else if (object.type === CLOUD) {locationsLimit = -1; cloudCounter++;} else throw parserError("expected object type code"); cursor += 1; @@ -181,6 +179,10 @@ function parseLevel(string) { level.objects.push(object); skipWhitespace(); } + + if(tileCounter>0 || cloudCounter>0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL: contains experimental elements"; + else document.getElementById("levelType").innerHTML = "STANDARD LEVEL: does not contain experimental elements"; + for (var i = 0; i < upconvertedObjects.length; i++) { level.objects.push(upconvertedObjects[i]); } From 8ee2577666f6902da238c7b28469e4ba7302348f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 15:26:18 -0500 Subject: [PATCH 230/577] Update Main.js --- Main.js | 161 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 89 insertions(+), 72 deletions(-) diff --git a/Main.js b/Main.js index 871e2ba1..e2ccc29c 100644 --- a/Main.js +++ b/Main.js @@ -1713,7 +1713,7 @@ var fruitColors1 = ["#ff0066","#ff36a6","#ff6b1f","#ff9900","#ff2600"]; var fruitColors2 = ["black","black","black","black","black"]; var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spike, support, box, bolt -var spikeColors2 = ["black", "black", "black", "black"]; +var spikeColors2 = ["gray", "black", "white", "black"]; var spikeColors3 = ["#333", "#333", "#333", "#777"]; var blockColors1 = [ @@ -1721,8 +1721,8 @@ var blockColors1 = [ ["#853641","#963c84","#753d88","#5d3a96","#3a3990"] ]; var blockColors2 = [ - ["#f2f2f2"], - ["#f2f2f2"] + ["#999"], + ["#999"] ]; var blockColors3 = [ ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"], @@ -1741,7 +1741,7 @@ var textStyle4 = ["" + fontSize + "px Impact", "#ff0", "#f00"]; var themeCounter = 0; -var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor +var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor, textStyle //["sky",], ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], @@ -2912,7 +2912,6 @@ function newPlatform(r, c, isOccupied){ } function drawGlass(r, c, isFixed) { - if(isFixed){ var grd = context.createLinearGradient(c*tileSize, r*tileSize, (c+1)*tileSize, (r+1)*tileSize); grd.addColorStop(0, "rgba(255,255,255,.4)"); grd.addColorStop(.1, "rgba(255,255,255,.5)"); @@ -2928,87 +2927,89 @@ function newPlatform(r, c, isOccupied){ context.fillStyle = grd; roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); - } - else{ - context.fillStyle = "rgba(255,255,255,.5)"; - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize*.5, r*tileSize); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.1); - context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.3); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.3); - context.lineTo(c*tileSize, r*tileSize); - context.closePath(); - context.fill(); + + if(!isFixed){ + var bgColor; + if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*')+2, background.length); + var r1, r2, b1, b2, g1, g2; + r1 = bgColor.substr(5, bgColor.indexOf(",")-5); + g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); + var shade = (r+1)*.03+.5; + if(shade>1) + shade = 1; + r2 = 255 + (r1-255) * shade; + g2 = 255 + (g1-255) * shade; + b2 = 255 + (b1-255) * shade; + context.strokeStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; + //context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; context.beginPath(); - context.moveTo(c*tileSize, r*tileSize+tileSize*.4); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.3); - context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.4); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.6); - context.lineTo(c*tileSize, r*tileSize+tileSize*.4); - context.closePath(); - context.fill(); + context.moveTo(c*tileSize+tileSize*.5, r*tileSize); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.15); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.4); + context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.35); + context.stroke(); context.beginPath(); - context.moveTo(c*tileSize, r*tileSize+tileSize*1); - context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.7); + context.moveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.4); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.5); context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.6); - context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.7); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*1); - context.lineTo(c*tileSize, r*tileSize+tileSize*1); - context.closePath(); - context.fill(); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.5); + context.stroke(); context.beginPath(); - context.moveTo(c*tileSize+tileSize, r*tileSize+tileSize*1); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*1); - context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.8); + context.moveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.6); context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.7); - context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.7); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.65); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.4); - context.lineTo(c*tileSize+tileSize, r*tileSize+tileSize*.5); - context.closePath(); - context.fill(); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.9); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*1); + context.stroke(); context.beginPath(); - context.moveTo(c*tileSize+tileSize, r*tileSize+tileSize*.4); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.3); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.4); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.3); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*0); - context.lineTo(c*tileSize+tileSize, r*tileSize+tileSize*0); - context.lineTo(c*tileSize+tileSize, r*tileSize+tileSize*.4); - context.closePath(); - context.fill(); + context.moveTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.7); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*1); + context.stroke(); context.beginPath(); - context.moveTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.15); - context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.05); - context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.15); - context.closePath(); - context.fill(); + context.moveTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.35); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.8); + context.stroke(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.35); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.1); + context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize); + context.stroke(); context.beginPath(); - context.moveTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.4); - context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.55); + context.moveTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.35); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.55, r*tileSize+tileSize*.45); context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.6); - context.lineTo(c*tileSize+tileSize*.55, r*tileSize+tileSize*.55); - context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.6); - context.lineTo(c*tileSize+tileSize*.65, r*tileSize+tileSize*.55); - context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.4); - context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.4); - context.closePath(); - context.fill(); + context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.7); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.15, r*tileSize+tileSize*.7); + context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*1); + context.stroke(); } } @@ -3030,7 +3031,6 @@ function newPlatform(r, c, isOccupied){ function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle, curlyOutline){ context.fillStyle = fillStyle; - var tileColor = "blue"; if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); @@ -3042,6 +3042,23 @@ function newPlatform(r, c, isOccupied){ else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); else roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); + /*var randomSpot = Math.floor(Math.random() * 5); //random spots on dirt + var randomColor = Math.floor(Math.random() * 5); + context.beginPath(); + switch(randomSpot){ + case 0: + context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 5, 0, 2*Math.PI); + case 1: + context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 4, 0, 2*Math.PI); + case 2: + context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 3, 0, 2*Math.PI); + case 3: + context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 2, 0, 2*Math.PI); + case 4: + context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 1, 0, 2*Math.PI); + } + context.stroke();*/ + if(isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { context.fillRect((c+1)*tileSize, (r+1)*tileSize, tileSize/6, tileSize/6); //context.globalCompositeOperation = "destination-out"; From 974e66d2be8077a8e89ef64dcecccd2893a2b2fa Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 15:26:41 -0500 Subject: [PATCH 231/577] Update Framework.html From 6256659086dce964e2e9dd0c9af05f9044221806 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 15:42:04 -0500 Subject: [PATCH 232/577] Update Main.js --- Main.js | 52 +++++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/Main.js b/Main.js index e2ccc29c..c69a6abc 100644 --- a/Main.js +++ b/Main.js @@ -2902,10 +2902,10 @@ function newPlatform(r, c, isOccupied){ function drawFoam(r, c) { context.fillStyle = "#ffccff"; - for (var i = 0; i < 4; i++) { - for (var j = 0; j < 4; j++) { + for (var i = 0; i < 5; i++) { + for (var j = 0; j < 5; j++) { context.beginPath(); - context.arc(c*tileSize + (i*2+1)*tileSize/8, r*tileSize + (j*2+1)*tileSize/8, tileSize/8, 0, 2*Math.PI); + context.arc(c*tileSize + (i*2+1)*tileSize/10, r*tileSize + (j*2+1)*tileSize/10, tileSize/10, 0, 2*Math.PI); context.fill(); } } @@ -2913,20 +2913,20 @@ function newPlatform(r, c, isOccupied){ function drawGlass(r, c, isFixed) { var grd = context.createLinearGradient(c*tileSize, r*tileSize, (c+1)*tileSize, (r+1)*tileSize); - grd.addColorStop(0, "rgba(255,255,255,.4)"); - grd.addColorStop(.1, "rgba(255,255,255,.5)"); - grd.addColorStop(.2, "rgba(255,255,255,.3)"); - grd.addColorStop(.3, "rgba(255,255,255,.4)"); - grd.addColorStop(.4, "rgba(255,255,255,.6)"); - grd.addColorStop(.5, "rgba(255,255,255,.5)"); - grd.addColorStop(.6, "rgba(255,255,255,.3)"); - grd.addColorStop(.7, "rgba(255,255,255,.4)"); - grd.addColorStop(.8, "rgba(255,255,255,.5)"); - grd.addColorStop(.9, "rgba(255,255,255,.6)"); - grd.addColorStop(1, "rgba(255,255,255,.5)"); + grd.addColorStop(0, "rgba(255,255,255,.6)"); + grd.addColorStop(.1, "rgba(255,255,255,.7)"); + grd.addColorStop(.2, "rgba(255,255,255,.5)"); + grd.addColorStop(.3, "rgba(255,255,255,.6)"); + grd.addColorStop(.4, "rgba(255,255,255,.8)"); + grd.addColorStop(.5, "rgba(255,255,255,.7)"); + grd.addColorStop(.6, "rgba(255,255,255,.5)"); + grd.addColorStop(.7, "rgba(255,255,255,.6)"); + grd.addColorStop(.8, "rgba(255,255,255,.7)"); + grd.addColorStop(.9, "rgba(255,255,255,.8)"); + grd.addColorStop(1, "rgba(255,255,255,.7)"); context.fillStyle = grd; - roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); + roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 5, true, false); if(!isFixed){ var bgColor; @@ -2939,9 +2939,9 @@ function newPlatform(r, c, isOccupied){ var shade = (r+1)*.03+.5; if(shade>1) shade = 1; - r2 = 255 + (r1-255) * shade; - g2 = 255 + (g1-255) * shade; - b2 = 255 + (b1-255) * shade; + r2 = 255 + (r1-255) * shade - 20; + g2 = 255 + (g1-255) * shade - 20; + b2 = 255 + (b1-255) * shade - 20; context.strokeStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; //context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; @@ -2969,9 +2969,9 @@ function newPlatform(r, c, isOccupied){ context.moveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.6); context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.6); context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.7); - context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.9); - context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*1); + context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.55, r*tileSize+tileSize*.9); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*1); context.stroke(); context.beginPath(); @@ -3005,10 +3005,16 @@ function newPlatform(r, c, isOccupied){ context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); context.lineTo(c*tileSize+tileSize*.55, r*tileSize+tileSize*.45); context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.6); - context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.7); + context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.7); context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); context.lineTo(c*tileSize+tileSize*.15, r*tileSize+tileSize*.7); - context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*1); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.96); + context.stroke(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.35); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.25); + context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.2); context.stroke(); } } From b13b987451515dceecd8e91669437f99d8ecfc70 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 21:02:10 -0500 Subject: [PATCH 233/577] Update Editor.css --- Editor.css | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/Editor.css b/Editor.css index fc015014..f1c6e153 100644 --- a/Editor.css +++ b/Editor.css @@ -1,11 +1,11 @@ @keyframes click_me { - 0% { background-color: buttonface; } - 50% { background-color: #ffff00; } - 100% { background-color: buttonface; } + 0% { background: buttonface; } + 50% { background: yellow; } + 100% { background: buttonface; } } button.click-me { - animation: click_me 1s linear infinite alternate; + animation: click_me 1s linear infinite; font-weight: bold; } @@ -23,7 +23,7 @@ body{ } button{ - background-image: linear-gradient(white, #f2f2f2); + background-image: linear-gradient(white, #e6e6e6); border: .4px solid black; border-radius: 3px; margin: 1px; @@ -36,7 +36,6 @@ button:focus{ } #levelTable{ - border: 10px solid black; margin: 0 auto; } @@ -77,6 +76,7 @@ table{ #controls{ background-color: aliceblue; width: 200px; + border: 2px solid black; } .header{ @@ -90,3 +90,12 @@ table{ #controlsRow button{ vertical-align: top; } + +#levelType{ + font-family: Arial; + font-size: 10pt; +} + +canvas{ + border: 2px solid black; +} From 101e34e1dda9f60fc654c38a08e32d810d81b20c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 21:02:27 -0500 Subject: [PATCH 234/577] Update Main.js --- Main.js | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/Main.js b/Main.js index c69a6abc..922e8569 100644 --- a/Main.js +++ b/Main.js @@ -1784,8 +1784,8 @@ function move(dr, dc) { var ate = false; var pushedObjects = []; - //track OpenGates that had objects on them - var occupiedOpenGates = getOccupiedOpenGateLocations(); + //track BrokenGlass that had objects on them + var occupiedBrokenGlass = getOccupiedBrokenGlassLocations(); if (isCollision()) { var newTile = level.map[newLocation]; @@ -1849,7 +1849,7 @@ function move(dr, dc) { moveObjects(pushedObjects, dr, dc, portalLocations, portalActivationLocations, changeLog, slitherAnimations); animationQueue.push(slitherAnimations); - occupiedOpenGates = combineOldAndNewGateOccupations(occupiedOpenGates); + occupiedBrokenGlass = combineOldAndNewGlassOccupations(occupiedBrokenGlass); // gravity loop var stateToAnimationIndex = {}; @@ -1895,7 +1895,7 @@ function move(dr, dc) { } } - occupiedOpenGates = combineOldAndNewGateOccupations(occupiedOpenGates); + occupiedBrokenGlass = combineOldAndNewGlassOccupations(occupiedBrokenGlass); // fall var dyingObjects = []; @@ -1941,7 +1941,7 @@ function move(dr, dc) { didAnything = true; } - occupiedOpenGates = closeGates(occupiedOpenGates, changeLog); + occupiedBrokenGlass = fixGlass(occupiedBrokenGlass, changeLog); if (!didAnything) break; Array.prototype.push.apply(animationQueue, exitAnimationQueue); @@ -1952,21 +1952,21 @@ function move(dr, dc) { render(); } -function combineOldAndNewGateOccupations(oldOccupiedOpenGates) +function combineOldAndNewGlassOccupations(oldOccupiedBrokenGlass) { - var newOccupiedOpenGates = getOccupiedOpenGateLocations(); - var newlyOccupiedOpenGates = getSetSubtract(newOccupiedOpenGates, oldOccupiedOpenGates); - return oldOccupiedOpenGates.concat(newlyOccupiedOpenGates); + var newOccupiedBrokenGlass = getOccupiedBrokenGlassLocations(); + var newlyOccupiedBrokenGlass = getSetSubtract(newOccupiedBrokenGlass, oldOccupiedBrokenGlass); + return oldOccupiedBrokenGlass.concat(newlyOccupiedBrokenGlass); } -function closeGates(oldOccupiedOpenGates, changeLog) +function fixGlass(oldOccupiedBrokenGlass, changeLog) { - var newOccupiedOpenGates = getOccupiedOpenGateLocations(); - var nowUnoccupiedOpenGates = getSetSubtract(oldOccupiedOpenGates, newOccupiedOpenGates); - for (var i = 0; i < nowUnoccupiedOpenGates.length; i++) { - paintTileAtLocation(nowUnoccupiedOpenGates[i], FIXEDGLASS, changeLog); + var newOccupiedBrokenGlass = getOccupiedBrokenGlassLocations(); + var nowUnoccupiedBrokenGlass = getSetSubtract(oldOccupiedBrokenGlass, newOccupiedBrokenGlass); + for (var i = 0; i < nowUnoccupiedBrokenGlass.length; i++) { + paintTileAtLocation(nowUnoccupiedBrokenGlass[i], FIXEDGLASS, changeLog); } - return newOccupiedOpenGates; + return newOccupiedBrokenGlass; } function getSetSubtract(array1, array2) { @@ -2230,7 +2230,7 @@ function getSnakes() { function getBlocks() { return getObjectsOfType(BLOCK); } -function getOccupiedOpenGateLocations() +function getOccupiedBrokenGlassLocations() { var result = []; for (var i = 0; i < level.map.length; i++) { @@ -3008,7 +3008,7 @@ function newPlatform(r, c, isOccupied){ context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.7); context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); context.lineTo(c*tileSize+tileSize*.15, r*tileSize+tileSize*.7); - context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.96); + context.lineTo(c*tileSize+tileSize*.02, r*tileSize+tileSize*.98); context.stroke(); context.beginPath(); @@ -3525,7 +3525,7 @@ function newPlatform(r, c, isOccupied){ } function drawCloud(c, x, y){ - c.fillStyle = "white"; + c.fillStyle = "black"; c.beginPath(); c.rect(x, y, tileSize, tileSize); c.fill(); From 4d69c8da05c8f22e336eba3061dbdb55806e6682 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 21:02:42 -0500 Subject: [PATCH 235/577] Update Framework.html From 0b06e61fc642c96272c991f38321e6764cf97f17 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 11 Feb 2020 21:03:27 -0500 Subject: [PATCH 236/577] Update Main.js --- Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.js b/Main.js index 922e8569..3d3df27b 100644 --- a/Main.js +++ b/Main.js @@ -3525,7 +3525,7 @@ function newPlatform(r, c, isOccupied){ } function drawCloud(c, x, y){ - c.fillStyle = "black"; + c.fillStyle = "white"; c.beginPath(); c.rect(x, y, tileSize, tileSize); c.fill(); From 0c91bbd81eff57bc178bd3aa87e2400f7028510f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 13 Feb 2020 15:53:18 -0500 Subject: [PATCH 237/577] Update Main.js --- Main.js | 528 +++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 446 insertions(+), 82 deletions(-) diff --git a/Main.js b/Main.js index 3d3df27b..7d43c169 100644 --- a/Main.js +++ b/Main.js @@ -40,6 +40,9 @@ var BLOCK = "b"; var FRUIT = "f"; var CLOUD = "c"; +var headRowMove; +var headColMove; + var tileSize = 34; var level; var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; @@ -1150,7 +1153,7 @@ function newFruit(location) { locations: [location], }; } -function newDirt(location) { +function newCloud(location) { var clouds = getObjectsOfType(CLOUD); clouds.sort(compareId); for (var i = 0; i < clouds.length; i++) { @@ -1193,7 +1196,7 @@ function paintAtLocation(location, changeLog) { } else if (object.type === FRUIT) { object.id = newFruit().id; } else if (object.type === CLOUD) { - object.id = newDirt().id; + object.id = newCloud().id; } else throw unreachable(); level.objects.push(object); changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); @@ -1273,7 +1276,7 @@ function paintAtLocation(location, changeLog) { } else if (paintBrushTileCode === CLOUD) { paintTileAtLocation(location, SPACE, changeLog); removeAnyObjectAtLocation(location, changeLog); - var object1 = newDirt(location) + var object1 = newCloud(location) level.objects.push(object1); changeLog.push([object1.type, object1.id, serializeObjectState(null), serializeObjectState(object1)]); } else throw unreachable(); @@ -1645,10 +1648,8 @@ function updateDirtyState() { if (dirtyState >= EDITOR_DIRTY) { // you should save saveLevelButton.classList.add("click-me"); - saveLevelButton.textContent = "*" + "Save Level"; } else { saveLevelButton.classList.remove("click-me"); - saveLevelButton.textContent = "Save Level"; } var saveProgressButton = document.getElementById("saveProgressButton"); @@ -1697,7 +1698,7 @@ function isAnyCheatcodeEnabled() { ); } var themeName = "Spring"; //Gooby -var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle; +var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle, experimentalColors; var curlyOutline = false; var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; @@ -1739,16 +1740,19 @@ var textStyle2 = ["" + fontSize + "px Impact", "#5702c6", "#ff0098"]; var textStyle3 = ["" + fontSize + "px Impact", "#BA145C", "#F75802"]; var textStyle4 = ["" + fontSize + "px Impact", "#ff0", "#f00"]; +var experimentalColors1 = ["white", "#ffccff"]; +var experimentalColors2 = ["white", "#FEFE28"]; + var themeCounter = 0; -var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor, textStyle +var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor, textStyle, experimentalColors //["sky",], - ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], - ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1], - ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4], - ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3], - ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2], - ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1] + ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], + ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], + ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], + ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], + ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], + ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] ]; @@ -1802,10 +1806,14 @@ function move(dr, dc) { ate = true; } else if (otherObject.type === CLOUD) { removeObject(otherObject, changeLog); - } else { - // push objects - if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; - } + } else if (isTileCodeAir(activeSnake, null, newTile, dr, dc)) { + var otherObject = findObjectAtLocation(newLocation); + if (otherObject != null) { + if (otherObject === activeSnake) return; // can't push yourself + // push objects + if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; + } + } else return; // can't go through that tile } } @@ -1996,19 +2004,6 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects } } var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); - if (dr === 1 && level.map[forwardLocation] === PLATFORM) { - // this platform holds us, unless we're going through it - var neighborLocations; - if (pushedObject.type === SNAKE) { - neighborLocations = []; - if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); - if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); - } else if (pushedObject.type === BLOCK) { - neighborLocations = pushedObject.locations; - } else throw asdf; - if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface - // we slip right past it - } var yetAnotherObject = findObjectAtLocation(forwardLocation); if (yetAnotherObject != null) { if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === CLOUD) { @@ -2019,7 +2014,7 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects // indirect pushing ourselves. // special check for when we're indirectly pushing the tip of our own tail. if (forwardLocation === pusher.locations[pusher.locations.length -1]) { - // for some reason this is ok. + // for some reason this is ok. ------------ THIS IS THE TAIL GLITCH continue; } return false; @@ -2332,13 +2327,14 @@ function render() { background = themes[themeCounter][1]; material = themes[themeCounter][2]; surface = themes[themeCounter][3]; + curlyOutline = themes[themeCounter][4]; snakeColors = themes[themeCounter][5]; blockColors = themes[themeCounter][6]; spikeColors = themes[themeCounter][7]; fruitColors = themes[themeCounter][8]; textStyle = themes[themeCounter][10]; + experimentalColors = themes[themeCounter][11]; - curlyOutline = themes[themeCounter][4]; if(background.substr(0,1) == "#") { context.fillStyle = background; context.fillRect(0, 0, canvas.width, canvas.height); @@ -2483,14 +2479,31 @@ function render() { for (var c = 0; c < level.width; c++) { var location = getLocation(level, r, c); var tileCode = level.map[location]; - drawTile(tileCode, r, c, level, location); + drawTile(tileCode, r, c, level, location, true); //draws all but walls } } } - - // objects - objects.forEach(drawObject); - + + for(var i = 0; i rowcol.r) { //last move up + switch(colorIndex){ + case 0: + orientation = 0; + break; + case 1: + orientation = 4; + break; + case 2: + orientation = 1; + break; + case 3: + orientation = 5; + break; + } + } + else if (lastRowcol.c < rowcol.c) { //last move right + switch(colorIndex){ + case 0: + orientation = 1; + break; + case 1: + orientation = 5; + break; + case 2: + orientation = 2; + break; + case 3: + orientation = 6; + break; + } + } + else if (lastRowcol.c > rowcol.c) { //last move left + switch(colorIndex){ + case 0: + orientation = 3; + break; + case 1: + orientation = 7; + break; + case 2: + orientation = 0; + break; + case 3: + orientation = 4; + break; + } + } + else orientation = 10; } else { // middle var cx = (rowcol.c + 0.5) * tileSize; var cy = (rowcol.r + 0.5) * tileSize; /*if(i % 2 == 0)*/ context.fillStyle = color; //else context.fillStyle = altColor; - var orientation; if (lastRowcol.r < rowcol.r) { - orientation = 0; context.beginPath(); context.moveTo((lastRowcol.c + 0) * tileSize, (lastRowcol.r + 0.5) * tileSize); context.lineTo((lastRowcol.c + 1) * tileSize, (lastRowcol.r + 0.5) * tileSize); context.arc(cx, cy, tileSize/2, 0, Math.PI); context.fill(); } else if (lastRowcol.r > rowcol.r) { - orientation = 2; context.beginPath(); context.moveTo((lastRowcol.c + 1) * tileSize, (lastRowcol.r + 0.5) * tileSize); context.lineTo((lastRowcol.c + 0) * tileSize, (lastRowcol.r + 0.5) * tileSize); context.arc(cx, cy, tileSize/2, Math.PI, 0); context.fill(); } else if (lastRowcol.c < rowcol.c) { - orientation = 3; context.beginPath(); context.moveTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 1) * tileSize); context.lineTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 0) * tileSize); + //roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); context.arc(cx, cy, tileSize/2, 1.5 * Math.PI, 2.5 * Math.PI); context.fill(); } else if (lastRowcol.c > rowcol.c) { - orientation = 1; context.beginPath(); context.moveTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 0) * tileSize); context.lineTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 1) * tileSize); @@ -2719,16 +2801,12 @@ function render() { } lastRowcol = rowcol; } - // eye - if (object.id === activeSnakeId) { - drawCircle(headRowcol.r, headRowcol.c, 0.5, "#fff"); - drawCircle(headRowcol.r, headRowcol.c, 0.2, "#000"); - } + drawFace(object.id, headRowcol.c, headRowcol.r, orientation); break; case BLOCK: drawBlock(object); break; - case FRUIT: //Gooby + case FRUIT: rowcol = getRowcol(level, object.locations[0]); var c = rowcol.c; var r = rowcol.r; @@ -2762,8 +2840,6 @@ function render() { context.fill(); } else drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); - - //context.drawImage(img3,rowcol.c*tileSize+(tileSize*.1), rowcol.r*tileSize+(tileSize*.1), tileSize*.8, tileSize*.8); break; case CLOUD: rowcol = getRowcol(level, object.locations[0]); @@ -2901,7 +2977,7 @@ function newPlatform(r, c, isOccupied){ } function drawFoam(r, c) { - context.fillStyle = "#ffccff"; + context.fillStyle = experimentalColors[1]; for (var i = 0; i < 5; i++) { for (var j = 0; j < 5; j++) { context.beginPath(); @@ -3021,7 +3097,7 @@ function newPlatform(r, c, isOccupied){ function drawWall(r, c, adjacentTiles) { //GOOBY //drawRect(r, c, "#976537"); - drawTileNew(r, c, isWall, 0.2, material, curlyOutline); + drawTileNew(r, c, isWall, 0.2, material); drawTileOutlines(r, c, isWall, 0.2, curlyOutline); context.save(); if(curlyOutline) drawBushes(r, c, isWall); @@ -3035,8 +3111,8 @@ function newPlatform(r, c, isOccupied){ } } - function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle, curlyOutline){ - context.fillStyle = fillStyle; + function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle){ + context.fillStyle = fillStyle; if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); @@ -3064,7 +3140,19 @@ function newPlatform(r, c, isOccupied){ context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 1, 0, 2*Math.PI); } context.stroke();*/ + } + + function drawCurves(r, c, adjacentTiles){ + drawCurves2(r, c, isWall, material); + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } + } + + function drawCurves2(r, c, isOccupied, material){ + context.fillStyle = material; if(isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { context.fillRect((c+1)*tileSize, (r+1)*tileSize, tileSize/6, tileSize/6); //context.globalCompositeOperation = "destination-out"; @@ -3145,7 +3233,6 @@ function newPlatform(r, c, isOccupied){ var complement = 1 - outlineThickness; var outlinePixels = outlineThickness * tileSize; var complementPixels = (1 - 2 * outlineThickness) * tileSize; - if (curlyOutline && !isOccupied(0, -1)){ if(!isOccupied(-1, 0) && isOccupied(1, 0)){ @@ -3254,17 +3341,16 @@ function newPlatform(r, c, isOccupied){ } function drawTileOutlines2(r, c, isOccupied, outlineThickness) { - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - var complementPixels = (1 - 2 * outlineThickness) * tileSize; - if (!isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - if (!isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (!isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + if (!isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!isOccupied( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + if (!isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); + if (!isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); } function drawSpikes(r, c, adjacentTiles) { @@ -3505,13 +3591,7 @@ function newPlatform(r, c, isOccupied){ var x = c * tileSize; var y = r * tileSize; context.fillStyle = fillStyle; - context.beginPath(); - context.moveTo(x + tileSize/2, y); - context.lineTo(x + tileSize, y + tileSize/2); - context.lineTo(x + tileSize/2, y + tileSize); - context.lineTo(x, y + tileSize/2); - context.lineTo(x + tileSize/2, y); - context.fill(); + roundRect(context, x, y, tileSize, tileSize, 10, true, false); } function drawCircle(r, c, radiusFactor, fillStyle) { context.fillStyle = fillStyle; @@ -3525,11 +3605,11 @@ function newPlatform(r, c, isOccupied){ } function drawCloud(c, x, y){ - c.fillStyle = "white"; - c.beginPath(); + c.fillStyle = experimentalColors[0]; + /*c.beginPath(); c.rect(x, y, tileSize, tileSize); c.fill(); - c.closePath(); + c.closePath();*/ c.beginPath(); c.moveTo(x+tileSize*0, y+tileSize*0); @@ -3554,6 +3634,290 @@ function newPlatform(r, c, isOccupied){ c.fill(); //c.stroke(); } + +function drawFace(snake, headCol, headRow, orientation){ + var x = headCol * tileSize; + var y = headRow * tileSize; + + var scaleFactor = 1.5; + var scale1; + var scale2; + var eye1 = tileSize*.8; + var eye2 = tileSize*.4; + + var eyeSize = tileSize/5; + var eyeRotation = 2; + var z1, z2, z3, z4, z5, z6, z7, z8; + var a1, a2, a3, a4, a5, a6, a7, a8; + var beakRotation = 1.5; + var arcDirection = false; + + switch(orientation){ + case 0: //red up and blue left + z1 = eye2; + z2 = tileSize-eye1; + z3 = eye2; + z4 = tileSize-eye2; + z5 = eye2; + z6 = tileSize-eye1; + z7 = eye2; + z8 = tileSize-eye2 + eyeRotation = 1.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize*.7; + a2 = tileSize-tileSize*.7; + a3 = tileSize*.7; + a4 = -tileSize*.3; + a5 = tileSize*.7; + a6 = tileSize*.3; + a7 = tileSize/6; + a8 = 0; + beakRotation = 1; + arcDirection = false; + break; + case 1: //red right and blue up + z1 = eye1; + z2 = eye2; + z3 = eye2; + z4 = eye2; + z5 = eye1; + z6 = eye2; + z7 = eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize*1.3; + a4 = tileSize*.7; + a5 = tileSize*.7; + a6 = tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = false; + break; + case 2: //red down and blue right + z1 = tileSize-eye2; + z2 = eye1; + z3 = tileSize-eye2; + z4 = eye2; + z5 = tileSize-eye2; + z6 = eye1; + z7 = tileSize-eye2; + z8 = eye2; + eyeRotation = 2.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize-tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize-tileSize*.7; + a4 = tileSize*1.3; + a5 = tileSize-tileSize*.7; + a6 = tileSize*.7; + a7 = tileSize/6; + a8 = 0; + beakRotation = 1; + arcDirection = true; + break; + case 3: //red left and blue down + z1 = tileSize-eye1; + z2 = tileSize-eye2; + z3 = tileSize-eye2; + z4 = tileSize-eye2; + z5 = tileSize-eye1; + z6 = tileSize-eye2; + z7 = tileSize-eye2; + z8 = tileSize-eye2; + eyeRotation = 3; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize-tileSize*.7; + a2 = tileSize-tileSize*.7; + a3 = tileSize-tileSize*1.3; + a4 = tileSize-tileSize*.7; + a5 = tileSize-tileSize*.7; + a6 = tileSize-tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = true; + break; + case 4: //green up and yellow right + z1 = tileSize-eye2; + z2 = tileSize-eye1; + z3 = tileSize-eye2; + z4 = tileSize-eye2; + z5 = tileSize-eye2; + z6 = tileSize-eye1; + z7 = tileSize-eye2; + z8 = tileSize-eye2 + eyeRotation = 2.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize-tileSize*.7; + a2 = tileSize-tileSize*.7; + a3 = tileSize-tileSize*.7; + a4 = -tileSize*.3; + a5 = tileSize-tileSize*.7; + a6 = tileSize*.3; + a7 = tileSize/6; + a8 = 0; + beakRotation = 1; + arcDirection = false; + break; + case 5: //green right and yellow down + z1 = eye1; + z2 = tileSize-eye2; + z3 = eye2; + z4 = tileSize-eye2; + z5 = eye1; + z6 = tileSize-eye2; + z7 = eye2; + z8 = tileSize-eye2; + eyeRotation = 3; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize*.7; + a2 = tileSize-tileSize*.7; + a3 = tileSize*1.3; + a4 = tileSize-tileSize*.7; + a5 = tileSize*.7; + a6 = tileSize-tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = false; + break; + case 6: //green down and yellow left + z1 = eye2; + z2 = eye1; + z3 = eye2; + z4 = eye2; + z5 = eye2; + z6 = eye1; + z7 = eye2; + z8 = eye2; + eyeRotation = 1.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize*.7; + a4 = tileSize*1.3; + a5 = tileSize*.7; + a6 = tileSize*.7; + a7 = tileSize/6; + a8 = 0; + beakRotation = 1; + arcDirection = true; + break; + case 7: //green left and yellow up + z1 = tileSize-eye1; + z2 = eye2; + z3 = tileSize-eye2; + z4 = eye2; + z5 = tileSize-eye1; + z6 = eye2; + z7 = tileSize-eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize-tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize-tileSize*1.3; + a4 = tileSize*.7; + a5 = tileSize-tileSize*.7; + a6 = tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = true; + break; + case 10: //single unit snake + z1 = eye1; + z2 = eye2; + z3 = eye2; + z4 = eye2; + z5 = eye1; + z6 = eye2; + z7 = eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize*1.3; + a4 = tileSize*.7; + a5 = tileSize*.7; + a6 = tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = false; + break; + } + + if (snake === activeSnakeId) { //draw eyes for active snake only + context.fillStyle = "white"; + context.save(); + context.scale(scale1,scale2); + context.beginPath(); + context.arc((x+z1)/scale1, (y+z2)/scale2, eyeSize, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + + context.fillStyle = "white"; + context.save(); + context.scale(scale1,scale2); + context.beginPath(); + context.arc((x+z3)/scale1, (y+z4)/scale2, eyeSize, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + + context.fillStyle = "black"; + context.save(); + context.scale(scale1,scale2); + context.beginPath(); + context.arc((x+z5)/scale1, (y+z6)/scale2, eyeSize/2, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + + context.fillStyle = "black"; + context.save(); + context.scale(scale1,scale2); + context.beginPath(); + context.arc((x+z7)/scale1, (y+z8)/scale2, eyeSize/2, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + } + + //beak + context.fillStyle = "yellow"; + context.beginPath(); + context.arc(x+a1, y+a2, tileSize/6, (beakRotation-1)*Math.PI, beakRotation*Math.PI, arcDirection); + context.lineTo(x+a3, y+a4); + context.lineTo(x+a5+a7, y+a6+a8); + context.closePath(); + context.fill(); +} function roundRect(ctx, x, y, width, height, radius, fill, stroke) { //Gooby if (typeof stroke === 'undefined') { From 7121c040347d3c61ffe8dd1e739089144dca71c7 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 13 Feb 2020 16:02:16 -0500 Subject: [PATCH 238/577] Update Main.js --- Main.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Main.js b/Main.js index 7d43c169..6838364c 100644 --- a/Main.js +++ b/Main.js @@ -2713,7 +2713,7 @@ function render() { orientation = 3; break; case 3: - orientation = 7; + orientation = 5; break; } } @@ -2729,7 +2729,7 @@ function render() { orientation = 1; break; case 3: - orientation = 5; + orientation = 7; break; } } @@ -2745,7 +2745,7 @@ function render() { orientation = 2; break; case 3: - orientation = 6; + orientation = 4; break; } } @@ -2761,7 +2761,7 @@ function render() { orientation = 0; break; case 3: - orientation = 4; + orientation = 6; break; } } From 14b529a90cac75a781976defb75df64f9d39c569 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 13 Feb 2020 16:26:23 -0500 Subject: [PATCH 239/577] Update Editor.css --- Editor.css | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Editor.css b/Editor.css index f1c6e153..8d365129 100644 --- a/Editor.css +++ b/Editor.css @@ -1,11 +1,11 @@ @keyframes click_me { - 0% { background: buttonface; } + 0% { background: linear-gradient(white, #e6e6e6); } 50% { background: yellow; } - 100% { background: buttonface; } + 100% { background: linear-gradient(white, #e6e6e6); } } button.click-me { - animation: click_me 1s linear infinite; + background: yellow; font-weight: bold; } @@ -24,16 +24,21 @@ body{ button{ background-image: linear-gradient(white, #e6e6e6); - border: .4px solid black; + border: none; border-radius: 3px; - margin: 1px; + margin: 2px; box-shadow: .5px .5px 1px black; } button:focus{ background-image: linear-gradient(#4b91ff, #055ce4); color: white; -} +} + +button:active{ + box-shadow: .5px .5px 1px black inset; + color: black; +} #levelTable{ margin: 0 auto; From 37478481186d2d7d7f18d015dfa25cc7c8360c77 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 13 Feb 2020 21:02:04 -0500 Subject: [PATCH 240/577] Update Main.js --- Main.js | 84 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 40 deletions(-) diff --git a/Main.js b/Main.js index 6838364c..79840d26 100644 --- a/Main.js +++ b/Main.js @@ -2663,15 +2663,17 @@ function render() { case SNAKE: var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); var lastRowcol = null + var nextRowcol = null var color = snakeColors[object.id % snakeColors.length]; var colorIndex = object.id % snakeColors.length; - //var altColor = snakeAltColors[object.id % snakeAltColors.length]; + var altColor = snakeAltColors[object.id % snakeAltColors.length]; var headRowcol; var orientation = 10; - for (var i = 0; i <= object.locations.length; i++) { + for (var i = object.locations.length-1; i > -1; i--) { //runs 3 times per move. When animation is comment out, alert(i) shows decrement 3x. When not comment out, it shows decrement 1x, then 2 not + //alert(i); var animation; var rowcol; - if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { + /*if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward rowcol = getRowcol(level, object.locations[i]); rowcol.r += animation[2] * (animationProgress - 1); @@ -2687,21 +2689,25 @@ function render() { // no animated tail needed break; } - } else { + } else {*/ rowcol = getRowcol(level, object.locations[i]); - } + //} + if(i != 0) nextRowcol = getRowcol(level, object.locations[i-1]); //new + if(i != object.locations.length) lastRowcol = getRowcol(level, object.locations[i+1]); //new + if (object.dead) rowcol.r += 0.5; rowcol.r += animationDisplacementRowcol.r; rowcol.c += animationDisplacementRowcol.c; if (i === 0) { // head context.fillStyle = color; - roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, 10, true, false); //draw head + //roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, 10, true, false); //draw head headRowcol = rowcol; //determines orientation of face lastRowcol = getRowcol(level, object.locations[1]); if (lastRowcol.r < rowcol.r) { //last move down + roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); //draw head switch(colorIndex){ case 0: orientation = 2; @@ -2717,7 +2723,8 @@ function render() { break; } } - else if (lastRowcol.r > rowcol.r) { //last move up + else if (lastRowcol.r > rowcol.r) { //last move up -------- this is the orientation when any snake falls (needs to be fixed) + roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); //draw head switch(colorIndex){ case 0: orientation = 0; @@ -2734,6 +2741,7 @@ function render() { } } else if (lastRowcol.c < rowcol.c) { //last move right + roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, {tr:10,br:10}, true, false); //draw head switch(colorIndex){ case 0: orientation = 1; @@ -2750,6 +2758,7 @@ function render() { } } else if (lastRowcol.c > rowcol.c) { //last move left + roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); //draw head switch(colorIndex){ case 0: orientation = 3; @@ -2765,41 +2774,36 @@ function render() { break; } } - else orientation = 10; + else { + roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, 10, true, false); //draw head + orientation = 10; + } } else { - // middle - var cx = (rowcol.c + 0.5) * tileSize; - var cy = (rowcol.r + 0.5) * tileSize; - /*if(i % 2 == 0)*/ context.fillStyle = color; - //else context.fillStyle = altColor; - if (lastRowcol.r < rowcol.r) { - context.beginPath(); - context.moveTo((lastRowcol.c + 0) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.lineTo((lastRowcol.c + 1) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.arc(cx, cy, tileSize/2, 0, Math.PI); - context.fill(); - } else if (lastRowcol.r > rowcol.r) { - context.beginPath(); - context.moveTo((lastRowcol.c + 1) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.lineTo((lastRowcol.c + 0) * tileSize, (lastRowcol.r + 0.5) * tileSize); - context.arc(cx, cy, tileSize/2, Math.PI, 0); - context.fill(); - } else if (lastRowcol.c < rowcol.c) { - context.beginPath(); - context.moveTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 1) * tileSize); - context.lineTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 0) * tileSize); - //roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); - context.arc(cx, cy, tileSize/2, 1.5 * Math.PI, 2.5 * Math.PI); - context.fill(); - } else if (lastRowcol.c > rowcol.c) { - context.beginPath(); - context.moveTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 0) * tileSize); - context.lineTo((lastRowcol.c + 0.5) * tileSize, (lastRowcol.r + 1) * tileSize); - context.arc(cx, cy, tileSize/2, 2.5 * Math.PI, 1.5 * Math.PI); - context.fill(); + var cx = rowcol.c * tileSize; + var cy = rowcol.r * tileSize; + if(i % 2 == 0) context.fillStyle = color; + else context.fillStyle = altColor; + + if (i === object.locations.length-1){ + if(nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false);} + else if(nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false);} + else if(nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false);} + else if(nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false);} + } + else{ + if (nextRowcol.r > rowcol.r && lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} + else if (nextRowcol.r > rowcol.r && lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} + else if (nextRowcol.r < rowcol.r && lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} + else if (nextRowcol.r < rowcol.r && lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} + + else if (nextRowcol.c > rowcol.c && lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} + else if (nextRowcol.c > rowcol.c && lastRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} + else if (nextRowcol.c < rowcol.c && lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} + else if (nextRowcol.c < rowcol.c && lastRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} + + else if (nextRowcol.c < rowcol.c && lastRowcol.c > rowcol.c || nextRowcol.c > rowcol.c && lastRowcol.c < rowcol.c || nextRowcol.r < rowcol.r && lastRowcol.r > rowcol.r || nextRowcol.r > rowcol.r && lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, 0, true, false);} } } - lastRowcol = rowcol; } drawFace(object.id, headRowcol.c, headRowcol.r, orientation); break; @@ -3910,7 +3914,7 @@ function drawFace(snake, headCol, headRow, orientation){ } //beak - context.fillStyle = "yellow"; + context.fillStyle = "#F9921C"; context.beginPath(); context.arc(x+a1, y+a2, tileSize/6, (beakRotation-1)*Math.PI, beakRotation*Math.PI, arcDirection); context.lineTo(x+a3, y+a4); From 4f23eaff1a9260027b14a06f8b8b9c56a70a8e85 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 13 Feb 2020 23:44:29 -0500 Subject: [PATCH 241/577] Update Main.js --- Main.js | 65 ++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 41 insertions(+), 24 deletions(-) diff --git a/Main.js b/Main.js index 79840d26..52f762cf 100644 --- a/Main.js +++ b/Main.js @@ -1909,7 +1909,7 @@ function move(dr, dc) { var dyingObjects = []; var fallingObjects = level.objects.filter(function(object) { if (object.type === FRUIT) return; // can't fall - if (object.type === CLOUD) return; // can't fall + if (object.type === BLOCK) return; // can't fall var theseDyingObjects = []; if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; // this object can fall. maybe more will fall with it too. we'll check those separately. @@ -2020,13 +2020,12 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects return false; } addIfNotPresent(pushedObjects, yetAnotherObject); - } else { - addIfNotPresent(forwardLocations, forwardLocation); } + addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work } } // check forward locations - for (var i = 0; i < forwardLocations.length; i++) { + for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform var forwardLocation = forwardLocations[i]; // many of these locations can be inside objects, // but that means the tile must be air, @@ -2037,10 +2036,9 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects if (dyingObjects != null) { if (tileCode === SPIKE) { // uh... which object was this again? - var deadObject = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); - if (deadObject.type === SNAKE) { + if (object.type === SNAKE) { // ouch! - addIfNotPresent(dyingObjects, deadObject); + addIfNotPresent(dyingObjects, object); continue; } } @@ -2109,20 +2107,21 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) var location = newLocations[i]; if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile var otherObject = findObjectAtLocation(location); - if (otherObject != null && otherObject !== object) return false; // blocked by object + if (otherObject != null && otherObject !== object) return; // blocked by object } // zappo presto! var oldState = serializeObjectState(object); object.locations = newLocations; + for (var i = 0; i < newLocations.length; i++) { + var location = newLocations[i]; + if (level.map[location] == FOAM) //changed this despite foam working perfectly without it + { + //dig + paintTileAtLocation(location, SPACE, changeLog); + } + } changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - animations.push([ - "t" + object.type, // TELEPORT_SNAKE | TELEPORT_BLOCK - object.id, - delta.r, - delta.c, - ]); - return true; } function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { @@ -2670,7 +2669,6 @@ function render() { var headRowcol; var orientation = 10; for (var i = object.locations.length-1; i > -1; i--) { //runs 3 times per move. When animation is comment out, alert(i) shows decrement 3x. When not comment out, it shows decrement 1x, then 2 not - //alert(i); var animation; var rowcol; /*if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { @@ -2689,11 +2687,33 @@ function render() { // no animated tail needed break; } - } else {*/ + } else { rowcol = getRowcol(level, object.locations[i]); - //} - if(i != 0) nextRowcol = getRowcol(level, object.locations[i-1]); //new - if(i != object.locations.length) lastRowcol = getRowcol(level, object.locations[i+1]); //new + }*/ + + /*if (i === object.locations.length-1 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { + // animate head slithering forward + rowcol = getRowcol(level, object.locations[i]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else if (i === 0) { + // animated tail? + if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { + // animate tail slithering to catch up + rowcol = getRowcol(level, object.locations[i + 1]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else { + // no animated tail needed + break; + } + } else { + rowcol = getRowcol(level, object.locations[i]); + }*/ + + rowcol = getRowcol(level, object.locations[i]); + if(i != 0) nextRowcol = getRowcol(level, object.locations[i-1]); + if(i != object.locations.length) lastRowcol = getRowcol(level, object.locations[i+1]); if (object.dead) rowcol.r += 0.5; rowcol.r += animationDisplacementRowcol.r; @@ -3997,10 +4017,7 @@ function findAnimation(animationTypes, objectId) { var currentAnimation = animationQueue[animationQueueCursor]; for (var i = 1; i < currentAnimation.length; i++) { var animation = currentAnimation[i]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === objectId) { - return animation; - } + if (animationTypes.indexOf(animation[0]) !== -1 && animation[1] === objectId) return animation; } } function findAnimationDisplacementRowcol(objectType, objectId) { From 761777712ed041d5f07ed132845fe5c771710eb8 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 14 Feb 2020 00:07:16 -0500 Subject: [PATCH 242/577] Update Main.js --- Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.js b/Main.js index 52f762cf..c84a9f03 100644 --- a/Main.js +++ b/Main.js @@ -1909,7 +1909,7 @@ function move(dr, dc) { var dyingObjects = []; var fallingObjects = level.objects.filter(function(object) { if (object.type === FRUIT) return; // can't fall - if (object.type === BLOCK) return; // can't fall + if (object.type === CLOUD) return; // can't fall var theseDyingObjects = []; if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; // this object can fall. maybe more will fall with it too. we'll check those separately. From 34b70dd86101ec7b78a754b789ec70f7c800233e Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 14 Feb 2020 20:00:30 -0500 Subject: [PATCH 243/577] Update Main.js --- Main.js | 128 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 67 insertions(+), 61 deletions(-) diff --git a/Main.js b/Main.js index c84a9f03..f325328a 100644 --- a/Main.js +++ b/Main.js @@ -1807,7 +1807,7 @@ function move(dr, dc) { } else if (otherObject.type === CLOUD) { removeObject(otherObject, changeLog); } else if (isTileCodeAir(activeSnake, null, newTile, dr, dc)) { - var otherObject = findObjectAtLocation(newLocation); + otherObject = findObjectAtLocation(newLocation); if (otherObject != null) { if (otherObject === activeSnake) return; // can't push yourself // push objects @@ -1834,7 +1834,7 @@ function move(dr, dc) { if (!ate) { // drag your tail forward var oldRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 1]); - var newRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 2]); + newRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 2]); if (!size1) { slitherAnimations.push([ SLITHER_TAIL, @@ -2020,12 +2020,13 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects return false; } addIfNotPresent(pushedObjects, yetAnotherObject); - } - addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work + if(level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work + } else + addIfNotPresent(forwardLocations, forwardLocation); } } // check forward locations - for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform + for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform, saw no effect but left new code var forwardLocation = forwardLocations[i]; // many of these locations can be inside objects, // but that means the tile must be air, @@ -2250,14 +2251,6 @@ function isAlive() { return countSnakes() > 0 && !isDead(); } - -var snakeAltColors = [ - "#ff6666", - "#66ff66", - "#6666ff", - "#ffff66", -]; - var activeSnakeId = null; var SLITHER_HEAD = "sh"; @@ -2657,6 +2650,21 @@ function render() { } } +function getTintedColor(color, v) { + if (color.length >6) { color= color.substring(1,color.length)} + var rgb = parseInt(color, 16); + var r = Math.abs(((rgb >> 16) & 0xFF)+v); if (r>255) r=r-(r-255); + var g = Math.abs(((rgb >> 8) & 0xFF)+v); if (g>255) g=g-(g-255); + var b = Math.abs((rgb & 0xFF)+v); if (b>255) b=b-(b-255); + r = Number(r < 0 || isNaN(r)) ? 0 : ((r > 255) ? 255 : r).toString(16); + if (r.length == 1) r = '0' + r; + g = Number(g < 0 || isNaN(g)) ? 0 : ((g > 255) ? 255 : g).toString(16); + if (g.length == 1) g = '0' + g; + b = Number(b < 0 || isNaN(b)) ? 0 : ((b > 255) ? 255 : b).toString(16); + if (b.length == 1) b = '0' + b; + return "#" + r + g + b; +} + function drawObject(object) { switch (object.type) { case SNAKE: @@ -2665,14 +2673,14 @@ function render() { var nextRowcol = null var color = snakeColors[object.id % snakeColors.length]; var colorIndex = object.id % snakeColors.length; - var altColor = snakeAltColors[object.id % snakeAltColors.length]; + //var altColor = snakeAltColors[object.id % snakeAltColors.length]; + var altColor = getTintedColor(color, 75); var headRowcol; var orientation = 10; - for (var i = object.locations.length-1; i > -1; i--) { //runs 3 times per move. When animation is comment out, alert(i) shows decrement 3x. When not comment out, it shows decrement 1x, then 2 not + for (var i = 0; i <= object.locations.length; i++) { var animation; var rowcol; - /*if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { - // animate head slithering forward + if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward rowcol = getRowcol(level, object.locations[i]); rowcol.r += animation[2] * (animationProgress - 1); rowcol.c += animation[3] * (animationProgress - 1); @@ -2689,44 +2697,21 @@ function render() { } } else { rowcol = getRowcol(level, object.locations[i]); - }*/ - - /*if (i === object.locations.length-1 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { - // animate head slithering forward - rowcol = getRowcol(level, object.locations[i]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else if (i === 0) { - // animated tail? - if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { - // animate tail slithering to catch up - rowcol = getRowcol(level, object.locations[i + 1]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else { - // no animated tail needed - break; - } - } else { - rowcol = getRowcol(level, object.locations[i]); - }*/ + } - rowcol = getRowcol(level, object.locations[i]); - if(i != 0) nextRowcol = getRowcol(level, object.locations[i-1]); - if(i != object.locations.length) lastRowcol = getRowcol(level, object.locations[i+1]); + lastRowcol = getRowcol(level, object.locations[i-1]); //closer to head + nextRowcol = getRowcol(level, object.locations[i+1]); //closer to tail if (object.dead) rowcol.r += 0.5; rowcol.r += animationDisplacementRowcol.r; rowcol.c += animationDisplacementRowcol.c; if (i === 0) { - // head context.fillStyle = color; - //roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, 10, true, false); //draw head headRowcol = rowcol; //determines orientation of face - lastRowcol = getRowcol(level, object.locations[1]); - if (lastRowcol.r < rowcol.r) { //last move down + nextRowcol = getRowcol(level, object.locations[1]); + if (nextRowcol.r < rowcol.r) { //last move down roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); //draw head switch(colorIndex){ case 0: @@ -2743,7 +2728,7 @@ function render() { break; } } - else if (lastRowcol.r > rowcol.r) { //last move up -------- this is the orientation when any snake falls (needs to be fixed) + else if (nextRowcol.r > rowcol.r) { //last move up -------- this is the orientation when any snake falls (needs to be fixed) roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); //draw head switch(colorIndex){ case 0: @@ -2760,7 +2745,7 @@ function render() { break; } } - else if (lastRowcol.c < rowcol.c) { //last move right + else if (nextRowcol.c < rowcol.c) { //last move right roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, {tr:10,br:10}, true, false); //draw head switch(colorIndex){ case 0: @@ -2777,7 +2762,7 @@ function render() { break; } } - else if (lastRowcol.c > rowcol.c) { //last move left + else if (nextRowcol.c > rowcol.c) { //last move left roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); //draw head switch(colorIndex){ case 0: @@ -2805,23 +2790,23 @@ function render() { else context.fillStyle = altColor; if (i === object.locations.length-1){ - if(nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false);} - else if(nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false);} - else if(nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false);} - else if(nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false);} + if(lastRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false);} + else if(lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false);} + else if(lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false);} + else if(lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false);} } else{ - if (nextRowcol.r > rowcol.r && lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} - else if (nextRowcol.r > rowcol.r && lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} - else if (nextRowcol.r < rowcol.r && lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} - else if (nextRowcol.r < rowcol.r && lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} + if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} + else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} + else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} + else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} - else if (nextRowcol.c > rowcol.c && lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} - else if (nextRowcol.c > rowcol.c && lastRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} - else if (nextRowcol.c < rowcol.c && lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} - else if (nextRowcol.c < rowcol.c && lastRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} + else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} + else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} + else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} + else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} - else if (nextRowcol.c < rowcol.c && lastRowcol.c > rowcol.c || nextRowcol.c > rowcol.c && lastRowcol.c < rowcol.c || nextRowcol.r < rowcol.r && lastRowcol.r > rowcol.r || nextRowcol.r > rowcol.r && lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, 0, true, false);} + else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, 0, true, false);} } } } @@ -3976,6 +3961,27 @@ function drawFace(snake, headCol, headRow, orientation){ ctx.stroke(); } } + +function shadeColor(color, percent) { + + var R = parseInt(color.substring(1,3),16); + var G = parseInt(color.substring(3,5),16); + var B = parseInt(color.substring(5,7),16); + + R = parseInt(R * (100 + percent) / 100); + G = parseInt(G * (100 + percent) / 100); + B = parseInt(B * (100 + percent) / 100); + + R = (R<255)?R:255; + G = (G<255)?G:255; + B = (B<255)?B:255; + + var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16)); + var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16)); + var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16)); + + return "#"+RR+GG+BB; +} function drawR(r,c,fillStyle){ //Gooby From b346ab86fc3ee92f44766fd13c0888f63854cbad Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 14 Feb 2020 20:20:38 -0500 Subject: [PATCH 244/577] Update Editor.css --- Editor.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor.css b/Editor.css index 8d365129..9b98df00 100644 --- a/Editor.css +++ b/Editor.css @@ -5,7 +5,7 @@ } button.click-me { - background: yellow; + animation: click_me 1s infinite; font-weight: bold; } From db7b8dd579fc1a05ab22767b595b73e77ca64f13 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 15 Feb 2020 00:11:26 -0500 Subject: [PATCH 245/577] Update Main.js --- Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.js b/Main.js index f325328a..23b97941 100644 --- a/Main.js +++ b/Main.js @@ -2674,7 +2674,7 @@ function getTintedColor(color, v) { var color = snakeColors[object.id % snakeColors.length]; var colorIndex = object.id % snakeColors.length; //var altColor = snakeAltColors[object.id % snakeAltColors.length]; - var altColor = getTintedColor(color, 75); + var altColor = getTintedColor(color, 50); var headRowcol; var orientation = 10; for (var i = 0; i <= object.locations.length; i++) { From 82d62329e412a549beb96c73afa8e42b98b3ddc6 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 16 Feb 2020 13:08:03 -0500 Subject: [PATCH 246/577] Update Main.js --- Main.js | 142 +++++++++++++++++++++++--------------------------------- 1 file changed, 59 insertions(+), 83 deletions(-) diff --git a/Main.js b/Main.js index 23b97941..aa54065b 100644 --- a/Main.js +++ b/Main.js @@ -1832,16 +1832,18 @@ function move(dr, dc) { ]; activeSnake.locations.unshift(newLocation); if (!ate) { - // drag your tail forward - var oldRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 1]); - newRowcol = getRowcol(level, activeSnake.locations[activeSnake.locations.length - 2]); - if (!size1) { - slitherAnimations.push([ - SLITHER_TAIL, - activeSnake.id, - newRowcol.r - oldRowcol.r, - newRowcol.c - oldRowcol.c, - ]); + for(var i = 1; i 0) neighborLocations.push(pushedObject.locations[j - 1]); + if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); + } else if (pushedObject.type === BLOCK) { + neighborLocations = pushedObject.locations; + } else throw asdf; + if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface + // we slip right past it + } var yetAnotherObject = findObjectAtLocation(forwardLocation); if (yetAnotherObject != null) { if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === CLOUD) { @@ -2020,7 +2035,7 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects return false; } addIfNotPresent(pushedObjects, yetAnotherObject); - if(level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work + //if(level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work } else addIfNotPresent(forwardLocations, forwardLocation); } @@ -2673,31 +2688,28 @@ function getTintedColor(color, v) { var nextRowcol = null var color = snakeColors[object.id % snakeColors.length]; var colorIndex = object.id % snakeColors.length; - //var altColor = snakeAltColors[object.id % snakeAltColors.length]; var altColor = getTintedColor(color, 50); var headRowcol; var orientation = 10; - for (var i = 0; i <= object.locations.length; i++) { + for (var i = 0; i < object.locations.length; i++) { var animation; var rowcol; - if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward + /*if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward rowcol = getRowcol(level, object.locations[i]); rowcol.r += animation[2] * (animationProgress - 1); rowcol.c += animation[3] * (animationProgress - 1); - } else if (i === object.locations.length) { + } else if (i != 0) { // animated tail? if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { // animate tail slithering to catch up - rowcol = getRowcol(level, object.locations[i - 1]); + rowcol = getRowcol(level, object.locations[i]); rowcol.r += animation[2] * (animationProgress - 1); rowcol.c += animation[3] * (animationProgress - 1); } else { // no animated tail needed break; } - } else { - rowcol = getRowcol(level, object.locations[i]); - } + } else*/ rowcol = getRowcol(level, object.locations[i]); lastRowcol = getRowcol(level, object.locations[i-1]); //closer to head nextRowcol = getRowcol(level, object.locations[i+1]); //closer to tail @@ -2705,6 +2717,11 @@ function getTintedColor(color, v) { if (object.dead) rowcol.r += 0.5; rowcol.r += animationDisplacementRowcol.r; rowcol.c += animationDisplacementRowcol.c; + lastRowcol.r += animationDisplacementRowcol.r; //attempts to correct falling orientation... + lastRowcol.c += animationDisplacementRowcol.c; //...and only works on tail + var cx = rowcol.c * tileSize; + var cy = rowcol.r * tileSize; + if (i === 0) { context.fillStyle = color; headRowcol = rowcol; @@ -2712,80 +2729,38 @@ function getTintedColor(color, v) { //determines orientation of face nextRowcol = getRowcol(level, object.locations[1]); if (nextRowcol.r < rowcol.r) { //last move down - roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); //draw head - switch(colorIndex){ - case 0: - orientation = 2; - break; - case 1: - orientation = 6; - break; - case 2: - orientation = 3; - break; - case 3: - orientation = 5; - break; - } + roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false); //draw head + if(colorIndex === 0) orientation = 2; + else if(colorIndex === 1) orientation = 6; + else if(colorIndex === 2) orientation = 3; + else if(colorIndex === 3) orientation = 5; } else if (nextRowcol.r > rowcol.r) { //last move up -------- this is the orientation when any snake falls (needs to be fixed) - roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); //draw head - switch(colorIndex){ - case 0: - orientation = 0; - break; - case 1: - orientation = 4; - break; - case 2: - orientation = 1; - break; - case 3: - orientation = 7; - break; - } + roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false); //draw head + if(colorIndex === 0) orientation = 0; + else if(colorIndex === 1) orientation = 4; + else if(colorIndex === 2) orientation = 1; + else if(colorIndex === 3) orientation = 7; } else if (nextRowcol.c < rowcol.c) { //last move right - roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, {tr:10,br:10}, true, false); //draw head - switch(colorIndex){ - case 0: - orientation = 1; - break; - case 1: - orientation = 5; - break; - case 2: - orientation = 2; - break; - case 3: - orientation = 4; - break; - } + roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false); //draw head + if(colorIndex === 0) orientation = 1; + else if(colorIndex === 1) orientation = 5; + else if(colorIndex === 2) orientation = 2; + else if(colorIndex === 3) orientation = 4; } else if (nextRowcol.c > rowcol.c) { //last move left - roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); //draw head - switch(colorIndex){ - case 0: - orientation = 3; - break; - case 1: - orientation = 7; - break; - case 2: - orientation = 0; - break; - case 3: - orientation = 6; - break; - } + roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false); //draw head + if(colorIndex === 0) orientation = 3; + else if(colorIndex === 1) orientation = 7; + else if(colorIndex === 2) orientation = 0; + else if(colorIndex === 3) orientation = 6; } else { - roundRect(context, rowcol.c*tileSize, rowcol.r*tileSize, tileSize, tileSize, 10, true, false); //draw head + roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); //draw head orientation = 10; } } else { - var cx = rowcol.c * tileSize; - var cy = rowcol.r * tileSize; if(i % 2 == 0) context.fillStyle = color; else context.fillStyle = altColor; @@ -2795,7 +2770,7 @@ function getTintedColor(color, v) { else if(lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false);} else if(lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false);} } - else{ + else if (i != object.locations.length-1 && i != object.locations.length){ if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} @@ -2808,6 +2783,7 @@ function getTintedColor(color, v) { else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, 0, true, false);} } + else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); } } drawFace(object.id, headRowcol.c, headRowcol.r, orientation); From e4ad054454f8fc2bbdcfb5f9f135c3aafe2480ac Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 16 Feb 2020 17:59:16 -0500 Subject: [PATCH 247/577] Update Main.js --- Main.js | 70 ++++++++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/Main.js b/Main.js index aa54065b..5dc7baf7 100644 --- a/Main.js +++ b/Main.js @@ -2683,7 +2683,9 @@ function getTintedColor(color, v) { function drawObject(object) { switch (object.type) { case SNAKE: + var falling = false; var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); + if (animationDisplacementRowcol.r != 0) falling = true; var lastRowcol = null var nextRowcol = null var color = snakeColors[object.id % snakeColors.length]; @@ -2694,40 +2696,46 @@ function getTintedColor(color, v) { for (var i = 0; i < object.locations.length; i++) { var animation; var rowcol; - /*if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward + if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward rowcol = getRowcol(level, object.locations[i]); rowcol.r += animation[2] * (animationProgress - 1); rowcol.c += animation[3] * (animationProgress - 1); - } else if (i != 0) { + } else if (i === object.locations.length) { // animated tail? if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { // animate tail slithering to catch up - rowcol = getRowcol(level, object.locations[i]); + rowcol = getRowcol(level, object.locations[i-1]); rowcol.r += animation[2] * (animationProgress - 1); rowcol.c += animation[3] * (animationProgress - 1); } else { // no animated tail needed break; } - } else*/ rowcol = getRowcol(level, object.locations[i]); + } else rowcol = getRowcol(level, object.locations[i]); lastRowcol = getRowcol(level, object.locations[i-1]); //closer to head nextRowcol = getRowcol(level, object.locations[i+1]); //closer to tail + var rc = rowcol; + var lrc = lastRowcol; + var nrc = nextRowcol; if (object.dead) rowcol.r += 0.5; rowcol.r += animationDisplacementRowcol.r; rowcol.c += animationDisplacementRowcol.c; - lastRowcol.r += animationDisplacementRowcol.r; //attempts to correct falling orientation... - lastRowcol.c += animationDisplacementRowcol.c; //...and only works on tail + lastRowcol.r += animationDisplacementRowcol.r; + lastRowcol.c += animationDisplacementRowcol.c; + nextRowcol.r += animationDisplacementRowcol.r; + nextRowcol.c += animationDisplacementRowcol.c; + var cx = rowcol.c * tileSize; var cy = rowcol.r * tileSize; if (i === 0) { context.fillStyle = color; headRowcol = rowcol; - + //determines orientation of face - nextRowcol = getRowcol(level, object.locations[1]); + if(!falling) nextRowcol = getRowcol(level, object.locations[1]); if (nextRowcol.r < rowcol.r) { //last move down roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false); //draw head if(colorIndex === 0) orientation = 2; @@ -2735,7 +2743,7 @@ function getTintedColor(color, v) { else if(colorIndex === 2) orientation = 3; else if(colorIndex === 3) orientation = 5; } - else if (nextRowcol.r > rowcol.r) { //last move up -------- this is the orientation when any snake falls (needs to be fixed) + else if (nextRowcol.r > rowcol.r) { //last move up roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false); //draw head if(colorIndex === 0) orientation = 0; else if(colorIndex === 1) orientation = 4; @@ -2761,29 +2769,29 @@ function getTintedColor(color, v) { orientation = 10; } } else { - if(i % 2 == 0) context.fillStyle = color; - else context.fillStyle = altColor; + if(i % 2 == 0) context.fillStyle = color; + else context.fillStyle = altColor; - if (i === object.locations.length-1){ - if(lastRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false);} - else if(lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false);} - else if(lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false);} - else if(lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false);} - } - else if (i != object.locations.length-1 && i != object.locations.length){ - if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} - else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} - else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} - else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} - - else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} - else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} - else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} - else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} - - else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, 0, true, false);} - } - else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); + if (i === object.locations.length-1) { + if(lastRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false);} + else if(lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false);} + else if(lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false);} + else if(lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false);} + } + else if (i != object.locations.length-1 && i != object.locations.length) { + if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} + else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} + else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} + else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} + + else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} + else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} + else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} + else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} + + else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, 0, true, false);} + } + else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); } } drawFace(object.id, headRowcol.c, headRowcol.r, orientation); From 537c14449f965b48a8c53f89e5ea2fa641a00482 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 12:56:29 -0500 Subject: [PATCH 248/577] Update Main.js --- Main.js | 146 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 106 insertions(+), 40 deletions(-) diff --git a/Main.js b/Main.js index 5dc7baf7..30b3579e 100644 --- a/Main.js +++ b/Main.js @@ -30,9 +30,9 @@ var ONEWAYWALLD = "d".charCodeAt(0); var ONEWAYWALLL = "l".charCodeAt(0); var ONEWAYWALLR = "r".charCodeAt(0); var FOAM = "f".charCodeAt(0); -var BROKENGLASS = "o".charCodeAt(0); -var FIXEDGLASS = "c".charCodeAt(0); -var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, BROKENGLASS, FIXEDGLASS, FOAM]; +var CLOSEDLIFT = "c".charCodeAt(0); +var OPENLIFT = "o".charCodeAt(0); +var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, CLOSEDLIFT, OPENLIFT, FOAM]; // object types var SNAKE = "s"; @@ -138,7 +138,7 @@ function parseLevel(string) { }); tileCode = SPACE; } - if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === BROKENGLASS || tileCode === FIXEDGLASS || tileCode === FOAM) tileCounter++; + if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === FOAM) tileCounter++; if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); level.map.push(tileCode); } @@ -518,8 +518,8 @@ document.addEventListener("keydown", function(event) { if (modifierMask === (CTRL|SHIFT)) { saveReplay(); break; } return; case "X".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BROKENGLASS); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(FIXEDGLASS); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOSEDLIFT); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(OPENLIFT); break; } if ( persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } return; case "F".charCodeAt(0): @@ -694,8 +694,8 @@ var paintButtonIdAndTileCodes = [ ["paintOneWayWallDButton", ONEWAYWALLD], ["paintOneWayWallLButton", ONEWAYWALLL], ["paintOneWayWallRButton", ONEWAYWALLR], - ["paintBrokenGlassButton", BROKENGLASS], - ["paintFixedGlassButton", FIXEDGLASS], + ["paintClosedLiftButton", CLOSEDLIFT], + ["paintOpenLiftButton", OPENLIFT], ["paintFoamButton", FOAM], ["paintSnakeButton", SNAKE], ["paintBlockButton", BLOCK], @@ -1557,12 +1557,12 @@ function describe(arg1, arg2) { case PORTAL: return "a Portal"; case PLATFORM: return "a Platform"; case WOODPLATFORM: return "a Wooden Platform"; - case ONEWAYWALLU: return "A One Way Wall (facing U)"; - case ONEWAYWALLD: return "A One Way Wall (facing D)"; - case ONEWAYWALLL: return "A One Way Wall (facing L)"; - case ONEWAYWALLR: return "A One Way Wall (facing R)"; - case BROKENGLASS: return "Broken Glass"; - case FIXEDGLASS: return "Fixed Glass"; + case ONEWAYWALLU: return "a One Way Wall (facing U)"; + case ONEWAYWALLD: return "a One Way Wall (facing D)"; + case ONEWAYWALLL: return "a One Way Wall (facing L)"; + case ONEWAYWALLR: return "a One Way Wall (facing R)"; + case CLOSEDLIFT: return "a Closed Lift"; + case OPENLIFT: return "an Open Lift"; case FOAM: return "Foam"; default: throw unreachable(); } @@ -1788,8 +1788,8 @@ function move(dr, dc) { var ate = false; var pushedObjects = []; - //track BrokenGlass that had objects on them - var occupiedBrokenGlass = getOccupiedBrokenGlassLocations(); + //track ClosedLifts that had objects on them + var occupiedClosedLift = getOccupiedClosedLiftLocations(); if (isCollision()) { var newTile = level.map[newLocation]; @@ -1859,7 +1859,7 @@ function move(dr, dc) { moveObjects(pushedObjects, dr, dc, portalLocations, portalActivationLocations, changeLog, slitherAnimations); animationQueue.push(slitherAnimations); - occupiedBrokenGlass = combineOldAndNewGlassOccupations(occupiedBrokenGlass); + occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); // gravity loop var stateToAnimationIndex = {}; @@ -1905,7 +1905,7 @@ function move(dr, dc) { } } - occupiedBrokenGlass = combineOldAndNewGlassOccupations(occupiedBrokenGlass); + occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); // fall var dyingObjects = []; @@ -1951,7 +1951,7 @@ function move(dr, dc) { didAnything = true; } - occupiedBrokenGlass = fixGlass(occupiedBrokenGlass, changeLog); + occupiedClosedLift = openLift(occupiedClosedLift, changeLog); if (!didAnything) break; Array.prototype.push.apply(animationQueue, exitAnimationQueue); @@ -1962,21 +1962,21 @@ function move(dr, dc) { render(); } -function combineOldAndNewGlassOccupations(oldOccupiedBrokenGlass) +function combineOldAndNewLiftOccupations(oldOccupiedClosedLift) { - var newOccupiedBrokenGlass = getOccupiedBrokenGlassLocations(); - var newlyOccupiedBrokenGlass = getSetSubtract(newOccupiedBrokenGlass, oldOccupiedBrokenGlass); - return oldOccupiedBrokenGlass.concat(newlyOccupiedBrokenGlass); + var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); + var newlyOccupiedClosedLift = getSetSubtract(newOccupiedClosedLift, oldOccupiedClosedLift); + return oldOccupiedClosedLift.concat(newlyOccupiedClosedLift); } -function fixGlass(oldOccupiedBrokenGlass, changeLog) +function openLift(oldOccupiedClosedLift, changeLog) { - var newOccupiedBrokenGlass = getOccupiedBrokenGlassLocations(); - var nowUnoccupiedBrokenGlass = getSetSubtract(oldOccupiedBrokenGlass, newOccupiedBrokenGlass); - for (var i = 0; i < nowUnoccupiedBrokenGlass.length; i++) { - paintTileAtLocation(nowUnoccupiedBrokenGlass[i], FIXEDGLASS, changeLog); + var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); + var nowUnoccupiedClosedLift = getSetSubtract(oldOccupiedClosedLift, newOccupiedClosedLift); + for (var i = 0; i < nowUnoccupiedClosedLift.length; i++) { + paintTileAtLocation(nowUnoccupiedClosedLift[i], OPENLIFT, changeLog); } - return newOccupiedBrokenGlass; + return newOccupiedClosedLift; } function getSetSubtract(array1, array2) { @@ -2143,7 +2143,7 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { switch (tileCode) { - case SPACE: case EXIT: case PORTAL: case BROKENGLASS: return true; + case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; case WOODPLATFORM: case FOAM: return pusher != null; case PLATFORM: return dr != 1; case ONEWAYWALLU: return dr != 1; @@ -2240,11 +2240,11 @@ function getSnakes() { function getBlocks() { return getObjectsOfType(BLOCK); } -function getOccupiedBrokenGlassLocations() +function getOccupiedClosedLiftLocations() { var result = []; for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === BROKENGLASS) { + if (level.map[i] === CLOSEDLIFT) { if (findObjectAtLocation(i)) result.push(i); } @@ -2635,11 +2635,11 @@ function render() { case ONEWAYWALLR: drawOneWayWall("#BACFD1", r, c, 0, 1); break; - case BROKENGLASS: - drawGlass(r, c, false); + case CLOSEDLIFT: + drawLift(r, c, false); break; - case FIXEDGLASS: - drawGlass(r, c, true); + case OPENLIFT: + drawLift(r, c, true); break; case FOAM: drawFoam(r, c); @@ -2719,7 +2719,11 @@ function getTintedColor(color, v) { var lrc = lastRowcol; var nrc = nextRowcol; - if (object.dead) rowcol.r += 0.5; + if (object.dead) { //if snake dies after moving left or right, head is positioned down + rowcol.r += .5; + lastRowcol.r += .5; + nextRowcol.r += .5; + } rowcol.r += animationDisplacementRowcol.r; rowcol.c += animationDisplacementRowcol.c; lastRowcol.r += animationDisplacementRowcol.r; @@ -2980,8 +2984,70 @@ function newPlatform(r, c, isOccupied){ } } - function drawGlass(r, c, isFixed) { - var grd = context.createLinearGradient(c*tileSize, r*tileSize, (c+1)*tileSize, (r+1)*tileSize); + function drawLift(r, c, isFixed) { + context.lineWidth = .5; + context.strokeStyle = "#777"; + if(!isFixed) { + context.fillStyle = "#e68a00"; + roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize, tileSize*.9, tileSize*.2, 2, true, true); + context.fillStyle = "#cc0000"; + roundRect(context, c*tileSize+tileSize*.3, r*tileSize+tileSize*.8, tileSize*.4, tileSize*.2, 2, true, true); + } + else if(isFixed) { + context.fillStyle = "#e68a00"; + roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize*.8, tileSize*.9, tileSize*.2, 2, true, true); + roundRect(context, c*tileSize+tileSize*.05, r*tileSize, tileSize*.9, tileSize*.2, 2, true, true); + + context.fillStyle = "#333"; + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.45); + context.bezierCurveTo(c*tileSize+tileSize*.16,r*tileSize+tileSize*.45,c*tileSize+tileSize*.16,r*tileSize+tileSize*.55,c*tileSize+tileSize*.2,r*tileSize+tileSize*.55); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); + context.closePath(); + context.fill(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.45); + context.bezierCurveTo(c*tileSize+tileSize*.84,r*tileSize+tileSize*.45,c*tileSize+tileSize*.84,r*tileSize+tileSize*.55,c*tileSize+tileSize*.8,r*tileSize+tileSize*.55); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.8); + context.closePath(); + context.fill(); + + /*context.beginPath(); + context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.9); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.1); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.1); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.9); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.9); + context.closePath(); + context.fill(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.9); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.1); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.1); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.9); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.9); + context.closePath(); + context.fill();*/ + } + + /*var grd = context.createLinearGradient(c*tileSize, r*tileSize, (c+1)*tileSize, (r+1)*tileSize); grd.addColorStop(0, "rgba(255,255,255,.6)"); grd.addColorStop(.1, "rgba(255,255,255,.7)"); grd.addColorStop(.2, "rgba(255,255,255,.5)"); @@ -3085,7 +3151,7 @@ function newPlatform(r, c, isOccupied){ context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.25); context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.2); context.stroke(); - } + }*/ } function drawWall(r, c, adjacentTiles) { //GOOBY From 0d9f99b089f3ae1bcc09b706452e207ec0b3cc77 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 12:57:51 -0500 Subject: [PATCH 249/577] Update index.html --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 45311c8e..c303ef7d 100644 --- a/index.html +++ b/index.html @@ -11,8 +11,8 @@
    -
    -
    + +
    @@ -548,7 +548,7 @@ - Gateway to Freedom + Gateway to Freedom LevelWorld From 156cad791c209515b24c3f6c3d7f657c87796c3d Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 12:58:20 -0500 Subject: [PATCH 250/577] Update Framework.html --- Framework.html | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Framework.html b/Framework.html index 902f5be1..dad26e2a 100644 --- a/Framework.html +++ b/Framework.html @@ -43,15 +43,14 @@ - Glass Ledges - + Scissor Lifts + Platforms - From 95fdfb5620f53ac0c1313fcde2e5c371afd34510 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 13:06:09 -0500 Subject: [PATCH 251/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index dad26e2a..889f84eb 100644 --- a/Framework.html +++ b/Framework.html @@ -57,7 +57,7 @@
    -
    STANDARD LEVEL: does not contain experimental elements
    +
    STANDARD LEVEL
    does not contain experimental elements
    Controls (hover for hotkeys):
    Arrows/WASD to move From b9729a352b33c8639d2bb1e26bb0719b91dc1b15 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 13:06:11 -0500 Subject: [PATCH 252/577] Update Main.js --- Main.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Main.js b/Main.js index 30b3579e..a9de3e1d 100644 --- a/Main.js +++ b/Main.js @@ -183,8 +183,8 @@ function parseLevel(string) { skipWhitespace(); } - if(tileCounter>0 || cloudCounter>0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL: contains experimental elements"; - else document.getElementById("levelType").innerHTML = "STANDARD LEVEL: does not contain experimental elements"; + if(tileCounter>0 || cloudCounter>0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL
    contains experimental elements"; + else document.getElementById("levelType").innerHTML = "STANDARD LEVEL
    does not contain experimental elements"; for (var i = 0; i < upconvertedObjects.length; i++) { level.objects.push(upconvertedObjects[i]); @@ -518,8 +518,6 @@ document.addEventListener("keydown", function(event) { if (modifierMask === (CTRL|SHIFT)) { saveReplay(); break; } return; case "X".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOSEDLIFT); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(OPENLIFT); break; } if ( persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } return; case "F".charCodeAt(0): @@ -543,6 +541,8 @@ document.addEventListener("keydown", function(event) { return; case "L".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOSEDLIFT); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(OPENLIFT); break; } if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLL); break; } return; case "G".charCodeAt(0): @@ -2987,16 +2987,17 @@ function newPlatform(r, c, isOccupied){ function drawLift(r, c, isFixed) { context.lineWidth = .5; context.strokeStyle = "#777"; + var strokeBool = false; if(!isFixed) { context.fillStyle = "#e68a00"; - roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize, tileSize*.9, tileSize*.2, 2, true, true); + roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); context.fillStyle = "#cc0000"; - roundRect(context, c*tileSize+tileSize*.3, r*tileSize+tileSize*.8, tileSize*.4, tileSize*.2, 2, true, true); + roundRect(context, c*tileSize+tileSize*.3, r*tileSize+tileSize*.8, tileSize*.4, tileSize*.2, 2, true, strokeBool); } else if(isFixed) { context.fillStyle = "#e68a00"; - roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize*.8, tileSize*.9, tileSize*.2, 2, true, true); - roundRect(context, c*tileSize+tileSize*.05, r*tileSize, tileSize*.9, tileSize*.2, 2, true, true); + roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize*.8, tileSize*.9, tileSize*.2, 2, true, strokeBool); + roundRect(context, c*tileSize+tileSize*.05, r*tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); context.fillStyle = "#333"; From ccf64259223fbaee0a3cb02a220f3ba575f7f248 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 13:08:34 -0500 Subject: [PATCH 253/577] Update Main.js --- Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.js b/Main.js index a9de3e1d..aa780d0e 100644 --- a/Main.js +++ b/Main.js @@ -2992,7 +2992,7 @@ function newPlatform(r, c, isOccupied){ context.fillStyle = "#e68a00"; roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); context.fillStyle = "#cc0000"; - roundRect(context, c*tileSize+tileSize*.3, r*tileSize+tileSize*.8, tileSize*.4, tileSize*.2, 2, true, strokeBool); + roundRect(context, c*tileSize+tileSize*.3, r*tileSize+tileSize*.8, tileSize*.4, tileSize*.2, {tl:2, tr:2}, true, strokeBool); } else if(isFixed) { context.fillStyle = "#e68a00"; From a454bdea6b06e99b4291ea3d0a725d93596b38ec Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 13:58:54 -0500 Subject: [PATCH 254/577] Update Main.js --- Main.js | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/Main.js b/Main.js index aa780d0e..7e4c5244 100644 --- a/Main.js +++ b/Main.js @@ -29,10 +29,10 @@ var ONEWAYWALLU = "u".charCodeAt(0); var ONEWAYWALLD = "d".charCodeAt(0); var ONEWAYWALLL = "l".charCodeAt(0); var ONEWAYWALLR = "r".charCodeAt(0); -var FOAM = "f".charCodeAt(0); +var BUBBLE = "b".charCodeAt(0); var CLOSEDLIFT = "c".charCodeAt(0); var OPENLIFT = "o".charCodeAt(0); -var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, CLOSEDLIFT, OPENLIFT, FOAM]; +var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, CLOSEDLIFT, OPENLIFT, BUBBLE]; // object types var SNAKE = "s"; @@ -138,7 +138,7 @@ function parseLevel(string) { }); tileCode = SPACE; } - if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === FOAM) tileCounter++; + if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === BUBBLE) tileCounter++; if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); level.map.push(tileCode); } @@ -522,7 +522,7 @@ document.addEventListener("keydown", function(event) { return; case "F".charCodeAt(0): if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(FOAM); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(BUBBLE); break; } return; case "D".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } @@ -530,6 +530,7 @@ document.addEventListener("keydown", function(event) { return; case "B".charCodeAt(0): if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(BUBBLE); break; } return; case "P".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } @@ -696,7 +697,7 @@ var paintButtonIdAndTileCodes = [ ["paintOneWayWallRButton", ONEWAYWALLR], ["paintClosedLiftButton", CLOSEDLIFT], ["paintOpenLiftButton", OPENLIFT], - ["paintFoamButton", FOAM], + ["paintBubbleButton", BUBBLE], ["paintSnakeButton", SNAKE], ["paintBlockButton", BLOCK], ["paintCloudButton", CLOUD], @@ -1563,7 +1564,7 @@ function describe(arg1, arg2) { case ONEWAYWALLR: return "a One Way Wall (facing R)"; case CLOSEDLIFT: return "a Closed Lift"; case OPENLIFT: return "an Open Lift"; - case FOAM: return "Foam"; + case BUBBLE: return "a Bubble"; default: throw unreachable(); } } @@ -1794,7 +1795,7 @@ function move(dr, dc) { if (isCollision()) { var newTile = level.map[newLocation]; if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile - if (newTile === FOAM) { + if (newTile === BUBBLE) { paintTileAtLocation(newLocation, SPACE, changeLog); } var otherObject = findObjectAtLocation(newLocation); @@ -2079,7 +2080,7 @@ function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations var oldPortals = getSetIntersection(portalLocations, object.locations); for (var i = 0; i < object.locations.length; i++) { object.locations[i] = offsetLocation(object.locations[i], dr, dc); - if (level.map[object.locations[i]] == FOAM) + if (level.map[object.locations[i]] == BUBBLE) { paintTileAtLocation(object.locations[i], SPACE, changeLog); } @@ -2131,7 +2132,7 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) object.locations = newLocations; for (var i = 0; i < newLocations.length; i++) { var location = newLocations[i]; - if (level.map[location] == FOAM) //changed this despite foam working perfectly without it + if (level.map[location] == BUBBLE) //changed this despite bubble working perfectly without it { //dig paintTileAtLocation(location, SPACE, changeLog); @@ -2144,7 +2145,7 @@ function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { switch (tileCode) { case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; - case WOODPLATFORM: case FOAM: return pusher != null; + case WOODPLATFORM: case BUBBLE: return pusher != null; case PLATFORM: return dr != 1; case ONEWAYWALLU: return dr != 1; case ONEWAYWALLD: return dr != -1; @@ -2641,8 +2642,8 @@ function render() { case OPENLIFT: drawLift(r, c, true); break; - case FOAM: - drawFoam(r, c); + case BUBBLE: + drawBubble(r, c); break; default: throw unreachable(); } @@ -2973,15 +2974,19 @@ function newPlatform(r, c, isOccupied){ context.lineWidth = 0; } - function drawFoam(r, c) { - context.fillStyle = experimentalColors[1]; - for (var i = 0; i < 5; i++) { - for (var j = 0; j < 5; j++) { - context.beginPath(); - context.arc(c*tileSize + (i*2+1)*tileSize/10, r*tileSize + (j*2+1)*tileSize/10, tileSize/10, 0, 2*Math.PI); - context.fill(); - } - } + function drawBubble(r, c) { + bubbleX = c*tileSize; + var grd = context.createRadialGradient(bubbleX, r*tileSize, 0, bubbleX, r*tileSize, tileSize); + grd.addColorStop(0, "rgba(255,255,255,.9)"); + grd.addColorStop(1, "rgba(255,255,255,.2)"); + context.fillStyle = grd; + context.lineWidth = .5; + context.strokeStyle = "rgba(200,200,200,.2)"; + + context.beginPath(); + context.arc(c*tileSize+tileSize*.5, r*tileSize+tileSize*.5, tileSize/2, 0, 2*Math.PI); + context.fill(); + context.stroke(); } function drawLift(r, c, isFixed) { From 339f594e2184590615c090fa05cbd1e549c4c99d Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 13:59:05 -0500 Subject: [PATCH 255/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index 889f84eb..e7f6482b 100644 --- a/Framework.html +++ b/Framework.html @@ -40,7 +40,7 @@ Experimental Elements Removeables - + Scissor Lifts From 127e3b9b83566be0e7e6fbba4c8d7a5eff29f9da Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 14:03:27 -0500 Subject: [PATCH 256/577] Update Main.js --- Main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Main.js b/Main.js index 7e4c5244..32706a3f 100644 --- a/Main.js +++ b/Main.js @@ -2724,6 +2724,7 @@ function getTintedColor(color, v) { rowcol.r += .5; lastRowcol.r += .5; nextRowcol.r += .5; + falling = true; } rowcol.r += animationDisplacementRowcol.r; rowcol.c += animationDisplacementRowcol.c; From 5297d4751c8785c988a77e8d8a748327fcc431e5 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 14:07:50 -0500 Subject: [PATCH 257/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index e7f6482b..1ca30a50 100644 --- a/Framework.html +++ b/Framework.html @@ -44,7 +44,7 @@ Scissor Lifts - + Platforms From f07b672f374a0b7a00c47689618db750b3f5f572 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 14:21:42 -0500 Subject: [PATCH 258/577] Update Main.js --- Main.js | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/Main.js b/Main.js index 32706a3f..5e7b2b25 100644 --- a/Main.js +++ b/Main.js @@ -3406,19 +3406,6 @@ function newPlatform(r, c, isOccupied){ } } - function drawTileOutlines2(r, c, isOccupied, outlineThickness) { - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - if (!isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isOccupied( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - if (!isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (!isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); - } - function drawSpikes(r, c, adjacentTiles) { var x = c * tileSize; var y = r * tileSize; @@ -3634,7 +3621,19 @@ function newPlatform(r, c, isOccupied){ var r = rowcol.r + animationDisplacementRowcol.r; var c = rowcol.c + animationDisplacementRowcol.c; context.fillStyle = blockColors[0][block.id % blockColors[0].length]; - drawTileOutlines2(r, c, isAlsoThisBlock, 0.3); + var outlineThickness = .2; + + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + if (!isAlsoThisBlock(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + if (!isAlsoThisBlock( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); + if (!isAlsoThisBlock(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!isAlsoThisBlock( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); + function isAlsoThisBlock(dc, dr) { for (var i = 0; i < rowcols.length; i++) { var otherRowcol = rowcols[i]; From eb9ea574749ceef44232516a48bdcc962cc90436 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 14:46:16 -0500 Subject: [PATCH 259/577] Update Main.js --- Main.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Main.js b/Main.js index 5e7b2b25..49eaa0e0 100644 --- a/Main.js +++ b/Main.js @@ -3605,12 +3605,12 @@ function newPlatform(r, c, isOccupied){ r2 = rTmp; c2 = cTmp; } - var xLo = (c1 + 0.4) * tileSize; - var yLo = (r1 + 0.4) * tileSize; - var xHi = (c2 + 0.6) * tileSize; - var yHi = (r2 + 0.6) * tileSize; + var xLo = (c1 + 0.3) * tileSize; + var yLo = (r1 + 0.3) * tileSize; + var xHi = (c2 + 0.45) * tileSize; + var yHi = (r2 + 0.45) * tileSize; context.fillStyle = color; - context.fillRect(xLo, yLo, xHi - xLo, yHi - yLo); + context.fillRect(xLo+.1*tileSize, yLo+.1*tileSize, xHi - xLo, yHi - yLo); } function drawBlock(block) { var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); From 2a68b297dfcb728705d9821b432865296eafaf4c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 17:21:40 -0500 Subject: [PATCH 260/577] Update Main.js --- Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.js b/Main.js index 49eaa0e0..bcba7d13 100644 --- a/Main.js +++ b/Main.js @@ -3610,7 +3610,7 @@ function newPlatform(r, c, isOccupied){ var xHi = (c2 + 0.45) * tileSize; var yHi = (r2 + 0.45) * tileSize; context.fillStyle = color; - context.fillRect(xLo+.1*tileSize, yLo+.1*tileSize, xHi - xLo, yHi - yLo); + context.fillRect(xLo+.15*tileSize, yLo+.15*tileSize, xHi - xLo, yHi - yLo); } function drawBlock(block) { var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); From 1e4e39d14450ec759717afbac5d6ed76cef00d5a Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 21:16:56 -0500 Subject: [PATCH 261/577] Update Main.js --- Main.js | 262 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 167 insertions(+), 95 deletions(-) diff --git a/Main.js b/Main.js index bcba7d13..fdca41b6 100644 --- a/Main.js +++ b/Main.js @@ -23,8 +23,8 @@ var SPIKE = "2".charCodeAt(0); var FRUIT_v0 = "3".charCodeAt(0); //legacy var EXIT = "4".charCodeAt(0); var PORTAL = "5".charCodeAt(0); -var PLATFORM = "p".charCodeAt(0); -var WOODPLATFORM = "w".charCodeAt(0); +var PLATFORM = "P".charCodeAt(0); +var WOODPLATFORM = "p".charCodeAt(0); var ONEWAYWALLU = "u".charCodeAt(0); var ONEWAYWALLD = "d".charCodeAt(0); var ONEWAYWALLL = "l".charCodeAt(0); @@ -32,7 +32,9 @@ var ONEWAYWALLR = "r".charCodeAt(0); var BUBBLE = "b".charCodeAt(0); var CLOSEDLIFT = "c".charCodeAt(0); var OPENLIFT = "o".charCodeAt(0); -var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, CLOSEDLIFT, OPENLIFT, BUBBLE]; +var LAVA = "v".charCodeAt(0); +var WATER = "w".charCodeAt(0); +var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, CLOSEDLIFT, OPENLIFT, BUBBLE, LAVA, WATER]; // object types var SNAKE = "s"; @@ -138,7 +140,7 @@ function parseLevel(string) { }); tileCode = SPACE; } - if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === BUBBLE) tileCounter++; + if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); level.map.push(tileCode); } @@ -508,6 +510,7 @@ document.addEventListener("keydown", function(event) { if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(WOODPLATFORM); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(WATER); break; } return; case "S".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } @@ -556,6 +559,7 @@ document.addEventListener("keydown", function(event) { if ( persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } return; case "V".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(LAVA); break; } if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } case "T".charCodeAt(0): toggleTheme(); break; @@ -698,6 +702,8 @@ var paintButtonIdAndTileCodes = [ ["paintClosedLiftButton", CLOSEDLIFT], ["paintOpenLiftButton", OPENLIFT], ["paintBubbleButton", BUBBLE], + ["paintLavaButton", LAVA], + ["paintWaterButton", WATER], ["paintSnakeButton", SNAKE], ["paintBlockButton", BLOCK], ["paintCloudButton", CLOUD], @@ -738,6 +744,7 @@ document.getElementById("themeButton").addEventListener("click", function() { function toggleTheme() { if(themeCounter"; } @@ -1565,6 +1572,8 @@ function describe(arg1, arg2) { case CLOSEDLIFT: return "a Closed Lift"; case OPENLIFT: return "an Open Lift"; case BUBBLE: return "a Bubble"; + case LAVA: return "Lava"; + case WATER: return "Water"; default: throw unreachable(); } } @@ -1876,7 +1885,7 @@ function move(dr, dc) { } // do portals separate from falling logic if (portalActivationLocations.length === 1) { - var portalAnimations = [200]; + var portalAnimations = [500]; if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { animationQueue.push(portalAnimations); } @@ -2036,7 +2045,7 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects return false; } addIfNotPresent(pushedObjects, yetAnotherObject); - //if(level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work + if(level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work } else addIfNotPresent(forwardLocations, forwardLocation); } @@ -2058,10 +2067,23 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects addIfNotPresent(dyingObjects, object); continue; } + + } + else if (tileCode === LAVA) { + if (object.type === SNAKE || object.type === BLOCK) { + addIfNotPresent(dyingObjects, object); + continue; + } + } + else if (tileCode === WATER) { + if (object.type === BLOCK) { + addIfNotPresent(dyingObjects, object); + continue; + } } - } // can't push into something solid return false; + } } } // the push is go @@ -2430,56 +2452,56 @@ function render() { })); } // begin by rendering the background connections for blocks - objects.forEach(function(object) { - if (object.type !== BLOCK) return; - var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); - var minR = Infinity; - var maxR = -Infinity; - var minC = Infinity; - var maxC = -Infinity; - object.locations.forEach(function(location) { - var rowcol = getRowcol(level, location); - if (rowcol.r < minR) minR = rowcol.r; - if (rowcol.r > maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var image = blockSupportRenderCache[object.id]; - if (image == null) { - // render the support beams to a buffer - blockSupportRenderCache[object.id] = image = document.createElement("canvas"); - image.width = (maxC - minC + 1) * tileSize; - image.height = (maxR - minR + 1) * tileSize; - var bufferContext = image.getContext("2d"); - // Make a stencil that excludes the insides of blocks. - // Then when we render the support beams, we won't see the supports inside the block itself. - bufferContext.beginPath(); - // Draw a path around the whole screen in the opposite direction as the rectangle paths below. - // This means that the below rectangles will be removing area from the greater rectangle. - bufferContext.rect(image.width, 0, -image.width, image.height); - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r - minR; - var c = rowcol.c - minC; - bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); - } - bufferContext.clip(); - for (var i = 0; i < object.locations.length - 1; i++) { - var rowcol1 = getRowcol(level, object.locations[i]); - rowcol1.r -= minR; - rowcol1.c -= minC; - var rowcol2 = getRowcol(level, object.locations[i + 1]); - rowcol2.r -= minR; - rowcol2.c -= minC; - var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; - drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - } - } - var r = minR + animationDisplacementRowcol.r; - var c = minC + animationDisplacementRowcol.c; - context.drawImage(image, c * tileSize, r * tileSize); - }); + objects.forEach(function(object) { + if (object.type !== BLOCK) return; + var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); + var minR = Infinity; + var maxR = -Infinity; + var minC = Infinity; + var maxC = -Infinity; + object.locations.forEach(function(location) { + var rowcol = getRowcol(level, location); + if (rowcol.r < minR) minR = rowcol.r; + if (rowcol.r > maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var image = blockSupportRenderCache[object.id]; + if (image == null) { + // render the support beams to a buffer + blockSupportRenderCache[object.id] = image = document.createElement("canvas"); + image.width = (maxC - minC + 1) * tileSize; + image.height = (maxR - minR + 1) * tileSize; + var bufferContext = image.getContext("2d"); + // Make a stencil that excludes the insides of blocks. + // Then when we render the support beams, we won't see the supports inside the block itself. + bufferContext.beginPath(); + // Draw a path around the whole screen in the opposite direction as the rectangle paths below. + // This means that the below rectangles will be removing area from the greater rectangle. + bufferContext.rect(image.width, 0, -image.width, image.height); + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r - minR; + var c = rowcol.c - minC; + bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); + } + bufferContext.clip(); + for (var i = 0; i < object.locations.length - 1; i++) { + var rowcol1 = getRowcol(level, object.locations[i]); + rowcol1.r -= minR; + rowcol1.c -= minC; + var rowcol2 = getRowcol(level, object.locations[i + 1]); + rowcol2.r -= minR; + rowcol2.c -= minC; + var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; + drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); + drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); + } + } + var r = minR + animationDisplacementRowcol.r; + var c = minC + animationDisplacementRowcol.c; + context.drawImage(image, c * tileSize, r * tileSize); + }); // terrain if (onlyTheseObjects == null) { @@ -2487,7 +2509,7 @@ function render() { for (var c = 0; c < level.width; c++) { var location = getLocation(level, r, c); var tileCode = level.map[location]; - drawTile(tileCode, r, c, level, location, true); //draws all but walls + drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids } } } @@ -2502,7 +2524,7 @@ function render() { for (var c = 0; c < level.width; c++) { location = getLocation(level, r, c); tileCode = level.map[location]; - if(tileCode === WALL) drawTile(tileCode, r, c, level, location, false); //draws only walls + if(tileCode === WALL) drawTile(tileCode, r, c, level, location, false); //draws only walls and liquids } } } @@ -2614,9 +2636,15 @@ function render() { drawQuarterPie(r, c, radiusFactor, snakeColors[3], 3); break; case PORTAL: - drawCircle(r, c, 0.8, "#888"); - drawCircle(r, c, 0.6, "#111"); - if (activePortalLocations.indexOf(location) !== -1) drawCircle(r, c, 0.3, "#666"); + var grd = context.createRadialGradient(c*tileSize+tileSize/2, r*tileSize+tileSize/2, tileSize/12, c*tileSize+tileSize/2, r*tileSize+tileSize/2, tileSize/2); + grd.addColorStop(0, "red"); + grd.addColorStop(0.17, "orange"); + grd.addColorStop(0.33, "yellow"); + grd.addColorStop(0.5, "green"); + grd.addColorStop(0.666, "blue"); + grd.addColorStop(1, "violet") + if (activePortalLocations.indexOf(location) !== -1) drawCircle(r, c, 1, grd); + else drawCircle(r, c, 1, "#111"); break; case PLATFORM: drawPlatform(r, c, getAdjacentTiles()); @@ -2625,16 +2653,16 @@ function render() { drawOneWayWall("#D38345", r, c, -1, 0); break; case ONEWAYWALLU: - drawOneWayWall("#BACFD1", r, c, -1, 0); + drawOneWayWall("#111", r, c, -1, 0); break; case ONEWAYWALLD: - drawOneWayWall("#BACFD1", r, c, 1, 0); + drawOneWayWall("#111", r, c, 1, 0); break; case ONEWAYWALLL: - drawOneWayWall("#BACFD1", r, c, 0, -1); + drawOneWayWall("#111", r, c, 0, -1); break; case ONEWAYWALLR: - drawOneWayWall("#BACFD1", r, c, 0, 1); + drawOneWayWall("#111", r, c, 0, 1); break; case CLOSEDLIFT: drawLift(r, c, false); @@ -2645,6 +2673,12 @@ function render() { case BUBBLE: drawBubble(r, c); break; + case LAVA: + drawLiquid(r, c, LAVA, getAdjacentTiles()); + break; + case WATER: + drawLiquid(r, c, WATER, getAdjacentTiles()); + break; default: throw unreachable(); } function getAdjacentTiles() { @@ -2692,6 +2726,7 @@ function getTintedColor(color, v) { var color = snakeColors[object.id % snakeColors.length]; var colorIndex = object.id % snakeColors.length; var altColor = getTintedColor(color, 50); + if(themeName==="Classic") altColor = color; var headRowcol; var orientation = 10; for (var i = 0; i < object.locations.length; i++) { @@ -2915,55 +2950,33 @@ function newPlatform(r, c, isOccupied){ } } - function drawOneWayWall(fillStyle, r, c, dr, dc) { - context.fillStyle = fillStyle; - if (dr == -1) - { - context.fillRect(c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15); - } - else if (dr == 1) - { - context.fillRect(c * tileSize - tileSize/15, (r + 1) * tileSize - tileSize/15 - tileSize/4, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15); - } - else if (dc == -1) - { - context.fillRect(c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15); - } - else if (dc == 1) - { - context.fillRect((c + 1) * tileSize - tileSize/15 - tileSize/4, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15); - } - - context.lineWidth = 3; - context.strokeStyle = "#777"; + function drawOneWayWall(fillStyle, r, c, dr, dc) { + context.lineWidth = 2; + context.strokeStyle = "#333"; context.beginPath(); - if (dr == -1) - { + if (dr == -1) { context.moveTo(c * tileSize, r * tileSize + tileSize/2); context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); context.stroke(); context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); } - else if (dr == 1) - { + else if (dr == 1) { context.moveTo(c * tileSize, r * tileSize + tileSize/2); context.lineTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); context.stroke(); context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); } - else if (dc == -1) - { + else if (dc == -1) { context.moveTo(c * tileSize + tileSize/2, r * tileSize); context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); context.stroke(); context.moveTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); } - else if (dc == 1) - { + else if (dc == 1) { context.moveTo(c * tileSize + tileSize/2, r * tileSize); context.lineTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); context.stroke(); @@ -2973,6 +2986,12 @@ function newPlatform(r, c, isOccupied){ context.stroke(); context.lineWidth = 0; + + context.fillStyle = fillStyle; + if (dr == -1) roundRect(context, c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15, 2, true, false); + else if (dr == 1) roundRect(context, c * tileSize - tileSize/15, (r + 1) * tileSize - tileSize/15 - tileSize/4, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15, 2, true, false); + else if (dc == -1) roundRect(context, c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15, 2, true, false); + else if (dc == 1) roundRect(context, (c + 1) * tileSize - tileSize/15 - tileSize/4, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15, 2, true, false); } function drawBubble(r, c) { @@ -2989,6 +3008,59 @@ function newPlatform(r, c, isOccupied){ context.fill(); context.stroke(); } + +function drawLiquid(r, c, type, adjacentTiles) { + newLiquid(r, c, type, isSameLiquid); + + function isSameLiquid(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === type; + } +} + +function newLiquid(r, c, type, isOccupied){ + var tubColor; + if(type == LAVA) { + context.fillStyle = "yellow"; + context.strokeStyle = "red"; + tubColor = "black"; + } + else { + context.fillStyle = "#1a8cff"; + context.strokeStyle = "#80ffe5"; + tubColor = "white"; + } + roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); + + context.lineWidth = 3; + context.beginPath(); + context.moveTo(c*tileSize, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.1, c*tileSize+tileSize/3, r*tileSize+tileSize*.1, c*tileSize+tileSize/2, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.3, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.3, c*tileSize+tileSize, r*tileSize+tileSize*.2); + context.moveTo(c*tileSize, r*tileSize+tileSize*.4); + context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.3, c*tileSize+tileSize/3, r*tileSize+tileSize*.3, c*tileSize+tileSize/2, r*tileSize+tileSize*.4); + context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.5, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.5, c*tileSize+tileSize, r*tileSize+tileSize*.4); + context.moveTo(c*tileSize, r*tileSize+tileSize*.6); + context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.5, c*tileSize+tileSize/3, r*tileSize+tileSize*.5, c*tileSize+tileSize/2, r*tileSize+tileSize*.6); + context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.7, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.7, c*tileSize+tileSize, r*tileSize+tileSize*.6); + context.moveTo(c*tileSize, r*tileSize+tileSize*.8); + context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.7, c*tileSize+tileSize/3, r*tileSize+tileSize*.7, c*tileSize+tileSize/2, r*tileSize+tileSize*.8); + context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.9, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.9, c*tileSize+tileSize, r*tileSize+tileSize*.8); + context.stroke(); + + context.fillStyle = tubColor; + if(!isOccupied(-1,0)) { + if(isOccupied(-1,-1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize-tileSize*.2, tileSize*.2, tileSize*1.2, 0, true, false); + else roundRect(context, c*tileSize-tileSize*.1, r*tileSize, tileSize*.2, tileSize, 0, true, false); + } + if(!isOccupied(1,0)) roundRect(context, c*tileSize+tileSize*.9, r*tileSize, tileSize*.2, tileSize, 0, true, false); + if(!isOccupied(0,1)) { + if(isOccupied(-1,1) && !isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); + else if(!isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize*1.3, tileSize*.2, 0, true, false); + else if(isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); + else roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize, tileSize*.2, 0, true, false); + } +} function drawLift(r, c, isFixed) { context.lineWidth = .5; From 49e7ef85db053c8e9c5cacb8b84c4eebb147e3cc Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 21:17:26 -0500 Subject: [PATCH 262/577] Update Framework.html --- Framework.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Framework.html b/Framework.html index 1ca30a50..b598a5f1 100644 --- a/Framework.html +++ b/Framework.html @@ -40,7 +40,7 @@ Experimental Elements Removeables - + Scissor Lifts @@ -50,6 +50,10 @@ Platforms + + + Liquids + @@ -57,7 +61,7 @@
    -
    STANDARD LEVEL
    does not contain experimental elements
    +
    STANDARD LEVEL
    does not contain experimental elements
    Controls (hover for hotkeys):
    Arrows/WASD to move From 54d1e1106574677093ee59e04df1549f803caa9f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 21:19:53 -0500 Subject: [PATCH 263/577] Update Main.js --- Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.js b/Main.js index fdca41b6..5ad366b2 100644 --- a/Main.js +++ b/Main.js @@ -3021,7 +3021,7 @@ function drawLiquid(r, c, type, adjacentTiles) { function newLiquid(r, c, type, isOccupied){ var tubColor; if(type == LAVA) { - context.fillStyle = "yellow"; + context.fillStyle = "#ffbf00"; context.strokeStyle = "red"; tubColor = "black"; } From e7a1a83e8ca0b17ff88f2ea08469d9b19a724e66 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 21:44:17 -0500 Subject: [PATCH 264/577] Update Main.js --- Main.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Main.js b/Main.js index 5ad366b2..880de3ea 100644 --- a/Main.js +++ b/Main.js @@ -895,16 +895,11 @@ function setPaintBrushTileCode(tileCode) { selectionEnd = null; return; } - if (typeof tileCode === "number" && tileCode !== PORTAL) { // fill in the selection fillSelection(tileCode); selectionStart = null; selectionEnd = null; return; - } - // ok, just select something else then. - selectionStart = null; - selectionEnd = null; } if (tileCode === SNAKE) { if (paintBrushTileCode === SNAKE) { From 17b1b39aaa4aa030a7f0b48450deafcc6ebc5d1f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 22:11:32 -0500 Subject: [PATCH 265/577] Update Main.js --- Main.js | 90 ++++++++++++++++++--------------------------------------- 1 file changed, 28 insertions(+), 62 deletions(-) diff --git a/Main.js b/Main.js index 880de3ea..3a31525e 100644 --- a/Main.js +++ b/Main.js @@ -29,18 +29,18 @@ var ONEWAYWALLU = "u".charCodeAt(0); var ONEWAYWALLD = "d".charCodeAt(0); var ONEWAYWALLL = "l".charCodeAt(0); var ONEWAYWALLR = "r".charCodeAt(0); +var CLOUD = "C".charCodeAt(0); var BUBBLE = "b".charCodeAt(0); var CLOSEDLIFT = "c".charCodeAt(0); var OPENLIFT = "o".charCodeAt(0); var LAVA = "v".charCodeAt(0); var WATER = "w".charCodeAt(0); -var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, CLOSEDLIFT, OPENLIFT, BUBBLE, LAVA, WATER]; +var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, CLOSEDLIFT, OPENLIFT, CLOUD, BUBBLE, LAVA, WATER]; // object types var SNAKE = "s"; var BLOCK = "b"; var FRUIT = "f"; -var CLOUD = "c"; var headRowMove; var headColMove; @@ -140,7 +140,7 @@ function parseLevel(string) { }); tileCode = SPACE; } - if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; + if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); level.map.push(tileCode); } @@ -156,13 +156,11 @@ function parseLevel(string) { }; // type - var cloudCounter = 0; object.type = string[cursor]; var locationsLimit; if (object.type === SNAKE) locationsLimit = -1; else if (object.type === BLOCK) locationsLimit = -1; else if (object.type === FRUIT) locationsLimit = 1; - else if (object.type === CLOUD) {locationsLimit = -1; cloudCounter++;} else throw parserError("expected object type code"); cursor += 1; @@ -185,7 +183,7 @@ function parseLevel(string) { skipWhitespace(); } - if(tileCounter>0 || cloudCounter>0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL
    contains experimental elements"; + if(tileCounter>0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL
    contains experimental elements"; else document.getElementById("levelType").innerHTML = "STANDARD LEVEL
    does not contain experimental elements"; for (var i = 0; i < upconvertedObjects.length; i++) { @@ -525,7 +523,6 @@ document.addEventListener("keydown", function(event) { return; case "F".charCodeAt(0): if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(BUBBLE); break; } return; case "D".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } @@ -701,12 +698,12 @@ var paintButtonIdAndTileCodes = [ ["paintOneWayWallRButton", ONEWAYWALLR], ["paintClosedLiftButton", CLOSEDLIFT], ["paintOpenLiftButton", OPENLIFT], + ["paintCloudButton", CLOUD], ["paintBubbleButton", BUBBLE], ["paintLavaButton", LAVA], ["paintWaterButton", WATER], ["paintSnakeButton", SNAKE], ["paintBlockButton", BLOCK], - ["paintCloudButton", CLOUD], ]; paintButtonIdAndTileCodes.forEach(function(pair) { var id = pair[0]; @@ -813,8 +810,6 @@ canvas.addEventListener("dblclick", function(event) { } else if (object.type === FRUIT) { // edit fruits, i guess paintBrushTileCode = FRUIT; - } else if (object.type === CLOUD) { - paintBrushTileCode = CLOUD; } else throw unreachable(); paintBrushTileCodeChanged(); } @@ -1156,19 +1151,6 @@ function newFruit(location) { locations: [location], }; } -function newCloud(location) { - var clouds = getObjectsOfType(CLOUD); - clouds.sort(compareId); - for (var i = 0; i < clouds.length; i++) { - if (clouds[i].id !== i) break; - } - return { - type: CLOUD, - id: i, - dead: false, // unused - locations: [location], - }; -} function paintAtLocation(location, changeLog) { if (typeof paintBrushTileCode === "number") { removeAnyObjectAtLocation(location, changeLog); @@ -1198,8 +1180,6 @@ function paintAtLocation(location, changeLog) { object.id = newBlock().id; } else if (object.type === FRUIT) { object.id = newFruit().id; - } else if (object.type === CLOUD) { - object.id = newCloud().id; } else throw unreachable(); level.objects.push(object); changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); @@ -1276,12 +1256,6 @@ function paintAtLocation(location, changeLog) { var object = newFruit(location) level.objects.push(object); changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); - } else if (paintBrushTileCode === CLOUD) { - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - var object1 = newCloud(location) - level.objects.push(object1); - changeLog.push([object1.type, object1.id, serializeObjectState(null), serializeObjectState(object1)]); } else throw unreachable(); render(); } @@ -1379,7 +1353,7 @@ function reduceChangeLog(changeLog) { changeLog.splice(i, 1); i--; } - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === CLOUD) { + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { for (var j = i + 1; j < changeLog.length; j++) { var otherChange = changeLog[j]; if (otherChange[0] === change[0] && otherChange[1] === change[1]) { @@ -1503,7 +1477,7 @@ function undoChanges(changes, changeLog) { if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; paintTileAtLocation(location, fromTileCode, changeLog); - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === CLOUD) { + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { // change object var type = change[0]; var id = change[1]; @@ -1566,6 +1540,7 @@ function describe(arg1, arg2) { case ONEWAYWALLR: return "a One Way Wall (facing R)"; case CLOSEDLIFT: return "a Closed Lift"; case OPENLIFT: return "an Open Lift"; + case CLOUD: return "a Cloud"; case BUBBLE: return "a Bubble"; case LAVA: return "Lava"; case WATER: return "Water"; @@ -1589,9 +1564,6 @@ function describe(arg1, arg2) { } if (arg1 === FRUIT) { return "Fruit"; - } - if (arg1 === CLOUD) { - return "Cloud"; } if (typeof arg1 === "object") return describe(arg1.type, arg1.id); throw unreachable(); @@ -1798,10 +1770,9 @@ function move(dr, dc) { if (isCollision()) { var newTile = level.map[newLocation]; - if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile - if (newTile === BUBBLE) { + if (newTile === BUBBLE || newTile === CLOUD) paintTileAtLocation(newLocation, SPACE, changeLog); - } + else if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile var otherObject = findObjectAtLocation(newLocation); if (otherObject != null) { if (otherObject === activeSnake) return; // can't push yourself @@ -1809,8 +1780,6 @@ function move(dr, dc) { // eat removeObject(otherObject, changeLog); ate = true; - } else if (otherObject.type === CLOUD) { - removeObject(otherObject, changeLog); } else if (isTileCodeAir(activeSnake, null, newTile, dr, dc)) { otherObject = findObjectAtLocation(newLocation); if (otherObject != null) { @@ -1916,7 +1885,6 @@ function move(dr, dc) { var dyingObjects = []; var fallingObjects = level.objects.filter(function(object) { if (object.type === FRUIT) return; // can't fall - if (object.type === CLOUD) return; // can't fall var theseDyingObjects = []; if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; // this object can fall. maybe more will fall with it too. we'll check those separately. @@ -2026,7 +1994,7 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects } var yetAnotherObject = findObjectAtLocation(forwardLocation); if (yetAnotherObject != null) { - if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === CLOUD) { + if (yetAnotherObject.type === FRUIT) { // not pushable return false; } @@ -2097,10 +2065,8 @@ function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations var oldPortals = getSetIntersection(portalLocations, object.locations); for (var i = 0; i < object.locations.length; i++) { object.locations[i] = offsetLocation(object.locations[i], dr, dc); - if (level.map[object.locations[i]] == BUBBLE) - { + if (level.map[object.locations[i]] == BUBBLE || level.map[object.locations[i]] == CLOUD) paintTileAtLocation(object.locations[i], SPACE, changeLog); - } } changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); animations.push([ @@ -2149,11 +2115,8 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) object.locations = newLocations; for (var i = 0; i < newLocations.length; i++) { var location = newLocations[i]; - if (level.map[location] == BUBBLE) //changed this despite bubble working perfectly without it - { - //dig + if (level.map[location] == BUBBLE || level.map[location] == CLOUD) //changed this despite bubble working perfectly without it paintTileAtLocation(location, SPACE, changeLog); - } } changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); } @@ -2519,14 +2482,24 @@ function render() { for (var c = 0; c < level.width; c++) { location = getLocation(level, r, c); tileCode = level.map[location]; - if(tileCode === WALL) drawTile(tileCode, r, c, level, location, false); //draws only walls and liquids + if(tileCode === WALL) drawTile(tileCode, r, c, level, location, false); //draws only walls + } + } + } + + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + location = getLocation(level, r, c); + tileCode = level.map[location]; + if(tileCode === CLOUD) drawTile(tileCode, r, c, level, location, false); //draws only clouds } } } for(var i = 0; i Date: Mon, 17 Feb 2020 22:14:30 -0500 Subject: [PATCH 266/577] Update Main.js --- Main.js | 5125 +++++++++---------------------------------------------- 1 file changed, 821 insertions(+), 4304 deletions(-) diff --git a/Main.js b/Main.js index 3a31525e..a858ef24 100644 --- a/Main.js +++ b/Main.js @@ -1,4310 +1,827 @@ -function unreachable() { return new Error("unreachable"); } -if (typeof VERSION !== "undefined") { - document.getElementById("versionSpan").innerHTML = - '' + VERSION.tag + ''; -} -/*$(document).ready(function() { - var fruits1 = getObjectsOfType(FRUIT); - $(fruits1[0]).jqFloat({ - width: 10, - height: 10, - speed: 100 - }); -});*/ - -var img3 = document.createElement('img'); //Gooby -//img3.src = '/Snakefall/Snakebird Images/Cherry2.png'; - -var canvas = document.getElementById("canvas"); - -var SPACE = "0".charCodeAt(0); -var WALL = "1".charCodeAt(0); -var SPIKE = "2".charCodeAt(0); -var FRUIT_v0 = "3".charCodeAt(0); //legacy -var EXIT = "4".charCodeAt(0); -var PORTAL = "5".charCodeAt(0); -var PLATFORM = "P".charCodeAt(0); -var WOODPLATFORM = "p".charCodeAt(0); -var ONEWAYWALLU = "u".charCodeAt(0); -var ONEWAYWALLD = "d".charCodeAt(0); -var ONEWAYWALLL = "l".charCodeAt(0); -var ONEWAYWALLR = "r".charCodeAt(0); -var CLOUD = "C".charCodeAt(0); -var BUBBLE = "b".charCodeAt(0); -var CLOSEDLIFT = "c".charCodeAt(0); -var OPENLIFT = "o".charCodeAt(0); -var LAVA = "v".charCodeAt(0); -var WATER = "w".charCodeAt(0); -var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, CLOSEDLIFT, OPENLIFT, CLOUD, BUBBLE, LAVA, WATER]; - -// object types -var SNAKE = "s"; -var BLOCK = "b"; -var FRUIT = "f"; - -var headRowMove; -var headColMove; - -var tileSize = 34; -var level; -var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; -var uneditStuff = {undoStack:[], redoStack:[], spanId:"editsSpan", undoButtonId:"uneditButton", redoButtonId:"reeditButton"}; -var paradoxes = []; -function loadLevel(newLevel) { - level = newLevel; - currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); - - activateAnySnakePlease(); - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - undoStuffChanged(unmoveStuff); - uneditStuff.undoStack = []; - uneditStuff.redoStack = []; - undoStuffChanged(uneditStuff); - blockSupportRenderCache = {}; - render(); -} - - -var magicNumber_v0 = "3tFRIoTU"; -var magicNumber = "HyRr4JK1"; -var exampleLevel = magicNumber_v0 + "&" + - "17&31" + - "?" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000000000000000" + - "0000000000000000000040000000000" + - "0000000000000110000000000000000" + - "0000000000000111100000000000000" + - "0000000000000011000000000000000" + - "0000000000000010000010000000000" + - "0000000000000010100011000000000" + - "0000001111111000110000000110000" + - "0000011111111111111111111110000" + - "0000011111111101111111111100000" + - "0000001111111100111111111100000" + - "0000001111111000111111111100000" + - "/" + - "s0 ?351&350&349/" + - "f0 ?328/" + - "f1 ?366/"; - -var testLevel_v0 = "3tFRIoTU&5&5?0005*00300024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/"; -var testLevel_v0_converted = "HyRr4JK1&5&5?0005*4024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/f0?8/"; - -function parseLevel(string) { - // magic number - var cursor = 0; - skipWhitespace(); - var versionTag = string.substr(cursor, magicNumber.length); - switch (versionTag) { - case magicNumber_v0: - case magicNumber: break; - default: throw new Error("not a snakefall level"); - } - cursor += magicNumber.length; - consumeKeyword("&"); - - var level = { - height: -1, - width: -1, - map: [], - objects: [], - }; - - // height, width - level.height = readInt(); - consumeKeyword("&"); - level.width = readInt(); - - // map - var mapData = readRun(); - mapData = decompressSerialization(mapData); - if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); - var upconvertedObjects = []; - var fruitCount = 0; - var tileCounter = 0; - for (var i = 0; i < mapData.length; i++) { - var tileCode = mapData[i].charCodeAt(0); - if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { - // fruit used to be a tile code. now it's an object. - upconvertedObjects.push({ - type: FRUIT, - id: fruitCount++, - dead: false, // unused - locations: [i], - }); - tileCode = SPACE; - } - if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; - if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); - level.map.push(tileCode); - } - - // objects - skipWhitespace(); - while (cursor < string.length) { - var object = { - type: "?", - id: -1, - dead: false, - locations: [], - }; - - // type - object.type = string[cursor]; - var locationsLimit; - if (object.type === SNAKE) locationsLimit = -1; - else if (object.type === BLOCK) locationsLimit = -1; - else if (object.type === FRUIT) locationsLimit = 1; - else throw parserError("expected object type code"); - cursor += 1; - - // id - object.id = readInt(); - - // locations - var locationsData = readRun(); - var locationStrings = locationsData.split("&"); - if (locationStrings.length === 0) throw parserError("locations must be non-empty"); - if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); - - locationStrings.forEach(function(locationString) { - var location = parseInt(locationString); - if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); - object.locations.push(location); - }); - - level.objects.push(object); - skipWhitespace(); - } - - if(tileCounter>0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL
    contains experimental elements"; - else document.getElementById("levelType").innerHTML = "STANDARD LEVEL
    does not contain experimental elements"; - - for (var i = 0; i < upconvertedObjects.length; i++) { - level.objects.push(upconvertedObjects[i]); - } - - return level; - - function skipWhitespace() { - while (" \n\t\r".indexOf(string[cursor]) !== -1) { - cursor += 1; - } - } - function consumeKeyword(keyword) { - skipWhitespace(); - if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); - cursor += 1; - } - function readInt() { - skipWhitespace(); - for (var i = cursor; i < string.length; i++) { - if ("0123456789".indexOf(string[i]) === -1) break; - } - var substring = string.substring(cursor, i); - if (substring.length === 0) throw parserError("expected int"); - cursor = i; - return parseInt(substring, 10); - } - function readRun() { - consumeKeyword("?"); - var endIndex = string.indexOf("/", cursor); - var substring = string.substring(cursor, endIndex); - cursor = endIndex + 1; - return substring; - } - function parserError(message) { - return new Error("parse error at position " + cursor + ": " + message); - } -} - -function serializeTileCode(tileCode) { - return String.fromCharCode(tileCode); -} - -function stringifyLevel(level) { - var output = magicNumber + "&"; - output += level.height + "&" + level.width + "\n"; - - output += "?\n"; - for (var r = 0; r < level.height; r++) { - output += " " + level.map.slice(r * level.width, (r + 1) * level.width).map(serializeTileCode).join("") + "\n"; - } - output += "/\n"; - - output += serializeObjects(level.objects); - - // sanity check - var shouldBeTheSame = parseLevel(output); - if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken - - return output; -} -function serializeObjects(objects) { - var output = ""; - for (var i = 0; i < objects.length; i++) { - var object = objects[i]; - output += object.type + object.id + " "; - output += "?" + object.locations.join("&") + "/\n"; - } - return output; -} -function serializeObjectState(object) { - if (object == null) return [0,[]]; - return [object.dead, copyArray(object.locations)]; -} - -var base66 = "----0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; -function compressSerialization(string) { - string = string.replace(/\s+/g, ""); - // run-length encode several 0's in a row, etc. - // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) - var result = ""; - var runStart = 0; - for (var i = 1; i < string.length + 1; i++) { - var runLength = i - runStart; - if (string[i] === string[runStart] && runLength < base66.length - 1) continue; - // end of run - if (runLength >= 4) { - // compress - result += "*" + base66[runLength] + string[runStart]; - } else { - // literal - result += string.substring(runStart, i); - } - runStart = i; - } - return result; -} -function decompressSerialization(string) { - string = string.replace(/\s+/g, ""); - var result = ""; - for (var i = 0; i < string.length; i++) { - if (string[i] === "*") { - i += 1; - var runLength = base66.indexOf(string[i]); - i += 1; - var char = string[i]; - for (var j = 0; j < runLength; j++) { - result += char; - } - } else { - result += string[i]; - } - } - return result; -} - -var replayMagicNumber = "nmGTi8PB"; -function stringifyReplay() { - var output = replayMagicNumber + "&"; - // only specify the snake id in an input if it's different from the previous. - // the first snake index is 0 to optimize for the single-snake case. - var currentSnakeId = 0; - for (var i = 0; i < unmoveStuff.undoStack.length; i++) { - var firstChange = unmoveStuff.undoStack[i][0]; - if (firstChange[0] !== "i") throw unreachable(); - var snakeId = firstChange[1]; - var dr = firstChange[2]; - var dc = firstChange[3]; - var directionCode; - if (dr ===-1 && dc === 0) directionCode = "u"; - else if (dr === 0 && dc ===-1) directionCode = "l"; - else if (dr === 1 && dc === 0) directionCode = "d"; - else if (dr === 0 && dc === 1) directionCode = "r"; - else throw unreachable(); - if (snakeId !== currentSnakeId) { - output += snakeId; // int to string - currentSnakeId = snakeId; - } - output += directionCode; - } - return output; -} -function parseAndLoadReplay(string) { - string = decompressSerialization(string); - var expectedPrefix = replayMagicNumber + "&"; - if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); - var cursor = expectedPrefix.length; - - // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. - activeSnakeId = 0; - while (cursor < string.length) { - var snakeIdStr = ""; - var c = string.charAt(cursor); - cursor += 1; - while ('0' <= c && c <= '9') { - snakeIdStr += c; - if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); - c = string.charAt(cursor); - cursor += 1; - } - if (snakeIdStr.length > 0) { - activeSnakeId = parseInt(snakeIdStr); - // don't just validate when switching snakes, but on every move. - } - - // doing a move. - if (!getSnakes().some(function(snake) { - return snake.id === activeSnakeId; - })) { - throw new Error("invalid snake id: " + activeSnakeId); - } - switch (c) { - case 'l': move( 0, -1); break; - case 'u': move(-1, 0); break; - case 'r': move( 0, 1); break; - case 'd': move( 1, 0); break; - default: throw new Error("replay string has invalid direction: " + c); - } - } - - // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. - reset(unmoveStuff); - document.getElementById("removeButton").classList.add("click-me"); -} - -var currentSerializedLevel; -function saveLevel() { - if (isDead()) return alert("Can't save while you're dead!"); - var serializedLevel = compressSerialization(stringifyLevel(level)); - currentSerializedLevel = serializedLevel; - var hash = "#level=" + serializedLevel; - expectHash = hash; - location.hash = hash; - - // This marks a starting point for solving the level. - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - editorHasBeenTouched = false; - undoStuffChanged(unmoveStuff); -} - -function saveReplay() { - if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); - // preserve the level in the url bar. - var hash = "#level=" + currentSerializedLevel; - if (dirtyState === REPLAY_DIRTY) { - // there is a replay to save - hash += "#replay=" + compressSerialization(stringifyReplay()); - } - expectHash = hash; - location.hash = hash; -} - -function deepEquals(a, b) { - if (a == null) return b == null; - if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; - if (Array.isArray(a)) { - if (!Array.isArray(b)) return false; - if (a.length !== b.length) return false; - for (var i = 0; i < a.length; i++) { - if (!deepEquals(a[i], b[i])) return false; - } - return true; - } - // must be objects - var aKeys = Object.keys(a); - var bKeys = Object.keys(b); - if (aKeys.length !== bKeys.length) return false; - aKeys.sort(); - bKeys.sort(); - if (!deepEquals(aKeys, bKeys)) return false; - for (var i = 0; i < aKeys.length; i++) { - if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; - } - return true; -} - -function getLocation(level, r, c) { - if (!isInBounds(level, r, c)) throw unreachable(); - return r * level.width + c; -} -function getRowcol(level, location) { - if (location < 0 || location >= level.width * level.height) throw unreachable(); - var r = Math.floor(location / level.width); - var c = location % level.width; - return {r:r, c:c}; -} -function isInBounds(level, r, c) { - if (c < 0 || c >= level.width) return false;; - if (r < 0 || r >= level.height) return false;; - return true; -} -function offsetLocation(location, dr, dc) { - var rowcol = getRowcol(level, location); - return getLocation(level, rowcol.r + dr, rowcol.c + dc); -} - -var SHIFT = 1; -var CTRL = 2; -var ALT = 4; -document.addEventListener("keydown", function(event) { - var modifierMask = ( - (event.shiftKey ? SHIFT : 0) | - (event.ctrlKey ? CTRL : 0) | - (event.altKey ? ALT : 0) - ); - switch (event.keyCode) { - case 37: // left - if (modifierMask === 0) { move(0, -1); break; } - return; - case 38: // up - if (modifierMask === 0) { move(-1, 0); break; } - return; - case 39: // right - if (modifierMask === 0) { move(0, 1); break; } - return; - case 40: // down - if (modifierMask === 0) { move(1, 0); break; } - return; - case 8: // backspace - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Q".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Z".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { undo(uneditStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL|SHIFT) { redo(uneditStuff); break; } - return; - case "Y".charCodeAt(0): - if (modifierMask === 0) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { redo(uneditStuff); break; } - return; - case "R".charCodeAt(0): - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } - if (modifierMask === 0) { reset(unmoveStuff); break; } - if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLR); break; } - return; - case 220: // backslash - if (modifierMask === 0) { toggleShowEditor(); break; } - return; - case "A".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, -1); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PORTAL); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { selectAll(); break; } - return; - case "E".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(EXIT); break; } - return; - case 46: // delete - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - return; - case "W".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(WOODPLATFORM); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(WATER); break; } - return; - case "S".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPIKE); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(SNAKE); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { saveLevel(); break; } - if (!persistentState.showEditor && modifierMask === CTRL) { saveReplay(); break; } - if (modifierMask === (CTRL|SHIFT)) { saveReplay(); break; } - return; - case "X".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } - return; - case "F".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } - return; - case "D".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLD); break; } - return; - case "B".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(BUBBLE); break; } - return; - case "P".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } - return; - case "U".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLU); break; } - return; - case "L".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOSEDLIFT); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(OPENLIFT); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLL); break; } - return; - case "G".charCodeAt(0): - if (modifierMask === 0) { toggleGrid(); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } - return; - case "C".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { toggleCollision(); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } - return; - case "V".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(LAVA); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } - case "T".charCodeAt(0): - toggleTheme(); break; - return; - case 32: // spacebar - case 9: // tab - if (modifierMask === 0) { switchSnakes( 1); break; } - if (modifierMask === SHIFT) { switchSnakes(-1); break; } - return; - case "1".charCodeAt(0): - case "2".charCodeAt(0): - case "3".charCodeAt(0): - case "4".charCodeAt(0): - var index = event.keyCode - "1".charCodeAt(0); - var delta; - if (modifierMask === 0) { - delta = 1; - } else if (modifierMask === SHIFT) { - delta = -1; - } else return; - if (isAlive()) { - (function() { - var snakes = findSnakesOfColor(index); - if (snakes.length === 0) return; - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; - } - } - activeSnakeId = snakes[0].id; - })(); - } - break; - case 27: // escape - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(null); break; } - return; - default: return; - } - event.preventDefault(); - render(); -}); - -document.getElementById("switchSnakesButton").addEventListener("click", function() { - switchSnakes(1); - render(); -}); -function switchSnakes(delta) { - if (!isAlive()) return; - var snakes = getSnakes(); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; - } - } - activeSnakeId = snakes[0].id; -} -document.getElementById("showGridButton").addEventListener("click", function() { - toggleGrid(); -}); -document.getElementById("saveProgressButton").addEventListener("click", function() { - saveReplay(); -}); -document.getElementById("restartButton").addEventListener("click", function() { - reset(unmoveStuff); - render(); -}); -document.getElementById("unmoveButton").addEventListener("click", function() { - undo(unmoveStuff); - render(); -}); -document.getElementById("removeButton").addEventListener("click", function() { - redo(unmoveStuff); - render(); -}); - -document.getElementById("showHideEditor").addEventListener("click", function() { - toggleShowEditor(); -}); -function toggleShowEditor() { - persistentState.showEditor = !persistentState.showEditor; - savePersistentState(); - showEditorChanged(); -} -function toggleGrid() { - persistentState.showGrid = !persistentState.showGrid; - savePersistentState(); - render(); -} - -["serializationTextarea", "shareLinkTextbox"].forEach(function(id) { - document.getElementById(id).addEventListener("keydown", function(event) { - // let things work normally - event.stopPropagation(); - }); -}); -document.getElementById("submitSerializationButton").addEventListener("click", function() { - var string = document.getElementById("serializationTextarea").value; - try { - var newLevel = parseLevel(string); - } catch (e) { - alert(e); - return; - } - loadLevel(newLevel); -}); -document.getElementById("shareLinkTextbox").addEventListener("focus", function() { - setTimeout(function() { - document.getElementById("shareLinkTextbox").select(); - }, 0); -}); - -var paintBrushTileCode = null; -var paintBrushSnakeColorIndex = 0; -var paintBrushBlockId = 0; -var paintBrushObject = null; -var selectionStart = null; -var selectionEnd = null; -var resizeDragAnchorRowcol = null; -var clipboardData = null; -var clipboardOffsetRowcol = null; -var paintButtonIdAndTileCodes = [ - ["resizeButton", "resize"], - ["selectButton", "select"], - ["pasteButton", "paste"], - ["paintSpaceButton", SPACE], - ["paintWallButton", WALL], - ["paintSpikeButton", SPIKE], - ["paintExitButton", EXIT], - ["paintFruitButton", FRUIT], - ["paintPortalButton", PORTAL], - ["paintPlatformButton", PLATFORM], - ["paintWoodPlatformButton", WOODPLATFORM], - ["paintOneWayWallUButton", ONEWAYWALLU], - ["paintOneWayWallDButton", ONEWAYWALLD], - ["paintOneWayWallLButton", ONEWAYWALLL], - ["paintOneWayWallRButton", ONEWAYWALLR], - ["paintClosedLiftButton", CLOSEDLIFT], - ["paintOpenLiftButton", OPENLIFT], - ["paintCloudButton", CLOUD], - ["paintBubbleButton", BUBBLE], - ["paintLavaButton", LAVA], - ["paintWaterButton", WATER], - ["paintSnakeButton", SNAKE], - ["paintBlockButton", BLOCK], -]; -paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - document.getElementById(id).addEventListener("click", function() { - setPaintBrushTileCode(tileCode); - }); -}); -document.getElementById("uneditButton").addEventListener("click", function() { - undo(uneditStuff); - render(); -}); -document.getElementById("reeditButton").addEventListener("click", function() { - redo(uneditStuff); - render(); -}); -document.getElementById("saveLevelButton").addEventListener("click", function() { - saveLevel(); -}); -document.getElementById("copyButton").addEventListener("click", function() { - copySelection(); -}); -document.getElementById("cutButton").addEventListener("click", function() { - cutSelection(); -}); -document.getElementById("cheatGravityButton").addEventListener("click", function() { - toggleGravity(); -}); -document.getElementById("cheatCollisionButton").addEventListener("click", function() { - toggleCollision(); -}); -document.getElementById("themeButton").addEventListener("click", function() { - toggleTheme(); -}); -function toggleTheme() { - if(themeCounter"; -} -function toggleGravity() { - isGravityEnabled = !isGravityEnabled; - isCollisionEnabled = true; - refreshCheatButtonText(); -} -function toggleCollision() { - isCollisionEnabled = !isCollisionEnabled; - isGravityEnabled = false; - refreshCheatButtonText(); -} -function refreshCheatButtonText() { - document.getElementById("cheatGravityButton").textContent = isGravityEnabled ? "Gravity: ON" : "Gravity: OFF"; - document.getElementById("cheatGravityButton").style.background = isGravityEnabled ? "" : "#f88"; - - document.getElementById("cheatCollisionButton").textContent = isCollisionEnabled ? "Collision: ON" : "Collision: OFF"; - document.getElementById("cheatCollisionButton").style.background = isCollisionEnabled ? "" : "#f88"; -} - -// be careful with location vs rowcol, because this variable is used when resizing -var lastDraggingRowcol = null; -var hoverLocation = null; -var draggingChangeLog = null; -canvas.addEventListener("mousedown", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - var location = getLocationFromEvent(event); - if (persistentState.showEditor && paintBrushTileCode != null) { - // editor tool - lastDraggingRowcol = getRowcol(level, location); - if (paintBrushTileCode === "select") selectionStart = location; - if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; - draggingChangeLog = []; - paintAtLocation(location, draggingChangeLog); - } else { - // playtime - var object = findObjectAtLocation(location); - if (object == null) return; - if (object.type !== SNAKE) return; - // active snake - activeSnakeId = object.id; - render(); - } -}); -canvas.addEventListener("dblclick", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - if (persistentState.showEditor && paintBrushTileCode === "select") { - // double click with select tool - var location = getLocationFromEvent(event); - var object = findObjectAtLocation(location); - if (object == null) return; - stopDragging(); - if (object.type === SNAKE) { - // edit snakes of this color - paintBrushTileCode = SNAKE; - paintBrushSnakeColorIndex = object.id % snakeColors.length; - } else if (object.type === BLOCK) { - // edit this particular block - paintBrushTileCode = BLOCK; - paintBrushBlockId = object.id; - } else if (object.type === FRUIT) { - // edit fruits, i guess - paintBrushTileCode = FRUIT; - } else throw unreachable(); - paintBrushTileCodeChanged(); - } -}); -document.addEventListener("mouseup", function(event) { - stopDragging(); -}); -function stopDragging() { - if (lastDraggingRowcol != null) { - // release the draggin' - lastDraggingRowcol = null; - paintBrushObject = null; - resizeDragAnchorRowcol = null; - pushUndo(uneditStuff, draggingChangeLog); - draggingChangeLog = null; - } -} -canvas.addEventListener("mousemove", function(event) { - if (!persistentState.showEditor) return; - var location = getLocationFromEvent(event); - var mouseRowcol = getRowcol(level, location); - if (lastDraggingRowcol != null) { - // Dragging Force - Through the Fruit and Flames - var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); - // we need to get rowcols for everything before we start dragging, because dragging might resize the world. - var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function(location) { - return getRowcol(level, location); - }); - path.forEach(function(rowcol) { - // convert to location at the last minute in case each of these steps is changing the coordinate system. - paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); - }); - lastDraggingRowcol = mouseRowcol; - hoverLocation = null; - } else { - // hovering - if (hoverLocation !== location) { - hoverLocation = location; - render(); - } - } -}); -canvas.addEventListener("mouseout", function() { - if (hoverLocation !== location) { - // turn off the hover when the mouse leaves - hoverLocation = null; - render(); - } -}); -function getLocationFromEvent(event) { - var r = Math.floor(eventToMouseY(event, canvas) / tileSize); - var c = Math.floor(eventToMouseX(event, canvas) / tileSize); - // since the canvas is centered, the bounding client rect can be half-pixel aligned, - // resulting in slightly out-of-bounds mouse events. - r = clamp(r, 0, level.height); - c = clamp(c, 0, level.width); - return getLocation(level, r, c); -} -function eventToMouseX(event, canvas) { return event.clientX - canvas.getBoundingClientRect().left; } -function eventToMouseY(event, canvas) { return event.clientY - canvas.getBoundingClientRect().top; } - -function selectAll() { - selectionStart = 0; - selectionEnd = level.map.length - 1; - setPaintBrushTileCode("select"); -} - -function setPaintBrushTileCode(tileCode) { - if (tileCode === "paste") { - // make sure we have something to paste - if (clipboardData == null) return; - } - if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { - // usually this means to fill in the selection - if (tileCode == null) { - // cancel selection - selectionStart = null; - selectionEnd = null; - return; - } - // fill in the selection - fillSelection(tileCode); - selectionStart = null; - selectionEnd = null; - return; - } - if (tileCode === SNAKE) { - if (paintBrushTileCode === SNAKE) { - // next snake color - paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; - } - } else if (tileCode === BLOCK) { - var blocks = getBlocks(); - if (paintBrushTileCode === BLOCK && blocks.length > 0) { - // cycle through block ids - blocks.sort(compareId); - if (paintBrushBlockId != null) { - (function() { - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id === paintBrushBlockId) { - i += 1; - if (i < blocks.length) { - // next block id - paintBrushBlockId = blocks[i].id; - } else { - // new block id - paintBrushBlockId = null; - } - return; - } - } - throw unreachable() - })(); - } else { - // first one - paintBrushBlockId = blocks[0].id; - } - } else { - // new block id - paintBrushBlockId = null; - } - } else if (tileCode == null) { - // escape - if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { - // stop editing this block, but keep the block brush selected - tileCode = BLOCK; - paintBrushBlockId = null; - } - } - paintBrushTileCode = tileCode; - paintBrushTileCodeChanged(); -} -function paintBrushTileCodeChanged() { - paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - var backgroundStyle = ""; - var textColor = ""; - if (tileCode === paintBrushTileCode) { - if (tileCode === SNAKE) { - // show the color of the active snake in the color of the button - backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; - } else { - backgroundStyle = "linear-gradient(#4b91ff, #055ce4)"; - textColor = "white"; - } - } - document.getElementById(id).style.background = backgroundStyle; - document.getElementById(id).style.color = textColor; - }); - - var isSelectionMode = paintBrushTileCode === "select"; - ["cutButton", "copyButton"].forEach(function (id) { - document.getElementById(id).disabled = !isSelectionMode; - }); - document.getElementById("pasteButton").disabled = clipboardData == null; - - render(); -} - -function cutSelection() { - copySelection(); - fillSelection(SPACE); - render(); -} -function copySelection() { - var selectedLocations = getSelectedLocations(); - if (selectedLocations.length === 0) return; - var selectedObjects = []; - selectedLocations.forEach(function(location) { - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(selectedObjects, object); - }); - setClipboardData({ - level: JSON.parse(JSON.stringify(level)), - selectedLocations: selectedLocations, - selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), - }); -} -function setClipboardData(data) { - // find the center - var minR = Infinity; - var maxR = -Infinity; - var minC = Infinity; - var maxC = -Infinity; - data.selectedLocations.forEach(function(location) { - var rowcol = getRowcol(data.level, location); - if (rowcol.r < minR) minR = rowcol.r; - if (rowcol.r > maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var offsetR = Math.floor((minR + maxR) / 2); - var offsetC = Math.floor((minC + maxC) / 2); - - clipboardData = data; - clipboardOffsetRowcol = {r:offsetR, c:offsetC}; - paintBrushTileCodeChanged(); -} -function fillSelection(tileCode) { - var changeLog = []; - var locations = getSelectedLocations(); - locations.forEach(function(location) { - if (level.map[location] !== tileCode) { - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; - } - removeAnyObjectAtLocation(location, changeLog); - }); - pushUndo(uneditStuff, changeLog); -} -function getSelectedLocations() { - if (selectionStart == null || selectionEnd == null) return []; - var rowcol1 = getRowcol(level, selectionStart); - var rowcol2 = getRowcol(level, selectionEnd); - var r1 = rowcol1.r; - var c1 = rowcol1.c; - var r2 = rowcol2.r; - var c2 = rowcol2.c; - if (r2 < r1) { - var tmp = r1; - r1 = r2; - r2 = tmp; - } - if (c2 < c1) { - var tmp = c1; - c1 = c2; - c2 = tmp; - } - var objects = []; - var locations = []; - for (var r = r1; r <= r2; r++) { - for (var c = c1; c <= c2; c++) { - var location = getLocation(level, r, c); - locations.push(location); - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(objects, object); - } - } - // select the rest of any partially-selected objects - objects.forEach(function(object) { - object.locations.forEach(function(location) { - addIfNotPresent(locations, location); - }); - }); - return locations; -} - -function setHeight(newHeight, changeLog) { - if (newHeight < level.height) { - // crop - for (var r = newHeight; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - // also delete non-space tiles - paintTileAtLocation(location, SPACE, changeLog); - } - } - level.map.splice(newHeight * level.width); - } else { - // expand - for (var r = level.height; r < newHeight; r++) { - for (var c = 0; c < level.width; c++) { - level.map.push(SPACE); - } - } - } - changeLog.push(["h", level.height, newHeight]); - level.height = newHeight; -} -function setWidth(newWidth, changeLog) { - if (newWidth < level.width) { - // crop - for (var r = level.height - 1; r >= 0; r--) { - for (var c = level.width - 1; c >= newWidth; c--) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, SPACE, changeLog); - level.map.splice(location, 1); - } - } - } else { - // expand - for (var r = level.height - 1; r >= 0; r--) { - var insertionPoint = level.width * (r + 1); - for (var c = level.width; c < newWidth; c++) { - // boy is this inefficient. ... YOLO! - level.map.splice(insertionPoint, 0, SPACE); - } - } - } - - var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); - level.objects.forEach(function(object) { - object.locations = object.locations.map(transformLocation); - }); - - changeLog.push(["w", level.width, newWidth]); - level.width = newWidth; -} - -function newSnake(color, location) { - var snakes = findSnakesOfColor(color); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id !== i * snakeColors.length + color) break; - } - return { - type: SNAKE, - id: i * snakeColors.length + color, - dead: false, - locations: [location], - }; -} -function newBlock(location) { - var blocks = getBlocks(); - blocks.sort(compareId); - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id !== i) break; - } - return { - type: BLOCK, - id: i, - dead: false, // unused - locations: [location], - }; -} -function newFruit(location) { - var fruits = getObjectsOfType(FRUIT); - fruits.sort(compareId); - for (var i = 0; i < fruits.length; i++) { - if (fruits[i].id !== i) break; - } - return { - type: FRUIT, - id: i, - dead: false, // unused - locations: [location], - }; -} -function paintAtLocation(location, changeLog) { - if (typeof paintBrushTileCode === "number") { - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, paintBrushTileCode, changeLog); - } else if (paintBrushTileCode === "resize") { - var toRowcol = getRowcol(level, location); - var dr = toRowcol.r - resizeDragAnchorRowcol.r; - var dc = toRowcol.c - resizeDragAnchorRowcol.c; - resizeDragAnchorRowcol = toRowcol; - if (dr !== 0) setHeight(level.height + dr, changeLog); - if (dc !== 0) setWidth(level.width + dc, changeLog); - } else if (paintBrushTileCode === "select") { - selectionEnd = location; - } else if (paintBrushTileCode === "paste") { - var hoverRowcol = getRowcol(level, location); - var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); - pastedData.selectedLocations.forEach(function(location) { - var tileCode = pastedData.level.map[location]; - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, tileCode, changeLog); - }); - pastedData.selectedObjects.forEach(function(object) { - // refresh the ids so there are no collisions. - if (object.type === SNAKE) { - object.id = newSnake(object.id % snakeColors.length).id; - } else if (object.type === BLOCK) { - object.id = newBlock().id; - } else if (object.type === FRUIT) { - object.id = newFruit().id; - } else throw unreachable(); - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - }); - } else if (paintBrushTileCode === SNAKE) { - var oldSnakeSerialization = serializeObjectState(paintBrushObject); - if (paintBrushObject != null) { - // keep dragging - if (paintBrushObject.locations[0] === location) return; // we just did that - // watch out for self-intersection - var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); - if (selfIntersectionIndex !== -1) { - // truncate from here back - paintBrushObject.locations.splice(selfIntersectionIndex); - } - } - - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - if (paintBrushObject == null) { - var thereWereNoSnakes = countSnakes() === 0; - paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); - level.objects.push(paintBrushObject); - if (thereWereNoSnakes) activateAnySnakePlease(); - } else { - // extend le snake - paintBrushObject.locations.unshift(location); - } - changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); - } else if (paintBrushTileCode === BLOCK) { - var objectHere = findObjectAtLocation(location); - if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { - // just start editing this block - paintBrushBlockId = objectHere.id; - } else { - // make a change - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - var thisBlock = null; - if (paintBrushBlockId != null) { - thisBlock = findBlockById(paintBrushBlockId); - } - var oldBlockSerialization = serializeObjectState(thisBlock); - if (thisBlock == null) { - // create new block - removeAnyObjectAtLocation(location, changeLog); - thisBlock = newBlock(location); - level.objects.push(thisBlock); - paintBrushBlockId = thisBlock.id; - } else { - var existingIndex = thisBlock.locations.indexOf(location); - if (existingIndex !== -1) { - // reclicking part of this object means to delete just part of it. - if (thisBlock.locations.length === 1) { - // goodbye - removeObject(thisBlock, changeLog); - paintBrushBlockId = null; - } else { - thisBlock.locations.splice(existingIndex, 1); - } - } else { - // add a tile to the block - removeAnyObjectAtLocation(location, changeLog); - thisBlock.locations.push(location); - } - } - changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); - delete blockSupportRenderCache[thisBlock.id]; - } - } else if (paintBrushTileCode === FRUIT) { - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - var object = newFruit(location) - level.objects.push(object); - changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); - } else throw unreachable(); - render(); -} - -function paintTileAtLocation(location, tileCode, changeLog) { - if (level.map[location] === tileCode) return; - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; -} - -function pushUndo(undoStuff, changeLog) { - // changeLog = [ - // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], - // // player input for snake 0, dr:-1, dc:0. has no effect on state. - // // "i" is always the first change in normal player movement. - // // if a changeLog does not start with "i", then it is an editor action. - // // animationQueue and freshlyRemovedAnimatedObjects - // // are used for animating re-move. - // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 - // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] - // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] - // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] - // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] - // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. - // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. - // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. - // 10, // the last change is always a declaration of the final width of the map. - // ]; - reduceChangeLog(changeLog); - if (changeLog.length === 0) return; - changeLog.push(level.width); - undoStuff.undoStack.push(changeLog); - undoStuff.redoStack = []; - paradoxes = []; - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; - - undoStuffChanged(undoStuff); -} -function reduceChangeLog(changeLog) { - for (var i = 0; i < changeLog.length - 1; i++) { - var change = changeLog[i]; - if (change[0] === "i") { - continue; // don't reduce player input - } else if (change[0] === "h") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "h") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "w") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "w") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "w") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "h") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "m") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "m" && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (change[2] === change[3]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === change[0] && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (deepEquals(change[2], change[3])) { - // no change - changeLog.splice(i, 1); - i--; - } - } else throw unreachable(); - } -} -function undo(undoStuff) { - if (undoStuff.undoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - undoOneFrame(undoStuff); - undoStuffChanged(undoStuff); -} -function reset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.undoStack.length > 0) { - undoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); -} -function undoOneFrame(undoStuff) { - var doThis = undoStuff.undoStack.pop(); - var redoChangeLog = []; - undoChanges(doThis, redoChangeLog); - if (redoChangeLog.length > 0) { - redoChangeLog.push(level.width); - undoStuff.redoStack.push(redoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; -} -function redo(undoStuff) { - if (undoStuff.redoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - redoOneFrame(undoStuff); - undoStuffChanged(undoStuff); -} -function unreset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.redoStack.length > 0) { - redoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); - - // don't animate the last frame - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; -} -function redoOneFrame(undoStuff) { - var doThis = undoStuff.redoStack.pop(); - var undoChangeLog = []; - undoChanges(doThis, undoChangeLog); - if (undoChangeLog.length > 0) { - undoChangeLog.push(level.width); - undoStuff.undoStack.push(undoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; -} -function undoChanges(changes, changeLog) { - var widthContext = changes.pop(); - var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); - for (var i = changes.length - 1; i >= 0; i--) { - var paradoxDescription = undoChange(changes[i]); - if (paradoxDescription != null) paradoxes.push(paradoxDescription); - } - - var lastChange = changes[changes.length - 1]; - if (lastChange[0] === "i") { - // replay animation - animationQueue = lastChange[4]; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = lastChange[5]; - animationStart = new Date().getTime(); - } - - function undoChange(change) { - // note: everything here is going backwards: to -> from - if (change[0] === "i") { - // no state change, but preserve the intention. - changeLog.push(change); - return null; - } else if (change[0] === "h") { - // change height - var fromHeight = change[1]; - var toHeight = change[2]; - if (level.height !== toHeight) return "Impossible"; - setHeight(fromHeight, changeLog); - } else if (change[0] === "w") { - // change width - var fromWidth = change[1]; - var toWidth = change[2]; - if (level.width !== toWidth) return "Impossible"; - setWidth(fromWidth, changeLog); - } else if (change[0] === "m") { - // change map tile - var location = transformLocation(change[1]); - var fromTileCode = change[2]; - var toTileCode = change[3]; - if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; - if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; - paintTileAtLocation(location, fromTileCode, changeLog); - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { - // change object - var type = change[0]; - var id = change[1]; - var fromDead = change[2][0]; - var toDead = change[3][0]; - var fromLocations = change[2][1].map(transformLocation); - var toLocations = change[3][1].map(transformLocation); - if (fromLocations.filter(function(location) { return location >= level.map.length; }).length > 0) { - return "Can't move " + describe(type, id) + " out of bounds"; - } - var object = findObjectOfTypeAndId(type, id); - if (toLocations.length !== 0) { - // should exist at this location - if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; - if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; - if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; - // doit - if (fromLocations.length !== 0) { - var oldState = serializeObjectState(object); - object.locations = fromLocations; - object.dead = fromDead; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - } else { - removeObject(object, changeLog); - } - } else { - // shouldn't exist - if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; - // doit - object = { - type: type, - id: id, - dead: fromDead, - locations: fromLocations, - }; - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - } - } else throw unreachable(); - } -} -function describe(arg1, arg2) { - // describe(0) -> "Space" - // describe(SNAKE, 0) -> "Snake 0 (Red)" - // describe(object) -> "Snake 0 (Red)" - // describe(BLOCK, 1) -> "Block 1" - // describe(FRUIT) -> "Fruit" - if (typeof arg1 === "number") { - switch (arg1) { - case SPACE: return "Space"; - case WALL: return "a Wall"; - case SPIKE: return "Spikes"; - case EXIT: return "an Exit"; - case PORTAL: return "a Portal"; - case PLATFORM: return "a Platform"; - case WOODPLATFORM: return "a Wooden Platform"; - case ONEWAYWALLU: return "a One Way Wall (facing U)"; - case ONEWAYWALLD: return "a One Way Wall (facing D)"; - case ONEWAYWALLL: return "a One Way Wall (facing L)"; - case ONEWAYWALLR: return "a One Way Wall (facing R)"; - case CLOSEDLIFT: return "a Closed Lift"; - case OPENLIFT: return "an Open Lift"; - case CLOUD: return "a Cloud"; - case BUBBLE: return "a Bubble"; - case LAVA: return "Lava"; - case WATER: return "Water"; - default: throw unreachable(); - } - } - if (arg1 === SNAKE) { - var color = (function() { - switch (snakeColors[arg2 % snakeColors.length]) { - case "#fd0c0b": return " (Red)"; - case "#18d11f": return " (Green)"; - case "#004cff": return " (Blue)"; - case "#fdc122": return " (Yellow)"; - default: throw unreachable(); - } - })(); - return "Snake " + arg2 + color; - } - if (arg1 === BLOCK) { - return "Block " + arg2; - } - if (arg1 === FRUIT) { - return "Fruit"; - } - if (typeof arg1 === "object") return describe(arg1.type, arg1.id); - throw unreachable(); -} - -function undoStuffChanged(undoStuff) { - var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; - document.getElementById(undoStuff.spanId).textContent = movesText; - document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; - document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; - - // render paradox display - var uniqueParadoxes = []; - var paradoxCounts = []; - paradoxes.forEach(function(paradoxDescription) { - var index = uniqueParadoxes.indexOf(paradoxDescription); - if (index !== -1) { - paradoxCounts[index] += 1; - } else { - uniqueParadoxes.push(paradoxDescription); - paradoxCounts.push(1); - } - }); - var paradoxDivContent = ""; - uniqueParadoxes.forEach(function(paradox, i) { - if (i > 0) paradoxDivContent += "
    \n"; - if (paradoxCounts[i] > 1) paradoxDivContent += "(" + paradoxCounts[i] + "x) "; - paradoxDivContent += "Time Travel Paradox! " + uniqueParadoxes[i]; - }); - document.getElementById("paradoxDiv").innerHTML = paradoxDivContent; - - updateDirtyState(); - - if (unmoveStuff.redoStack.length === 0) { - document.getElementById("removeButton").classList.remove("click-me"); - } -} - -var CLEAN_NO_TIMELINES = 0; -var CLEAN_WITH_REDO = 1; -var REPLAY_DIRTY = 2; -var EDITOR_DIRTY = 3; -var dirtyState = CLEAN_NO_TIMELINES; -var editorHasBeenTouched = false; -function updateDirtyState() { - if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { - dirtyState = EDITOR_DIRTY; - } else if (unmoveStuff.undoStack.length > 0) { - dirtyState = REPLAY_DIRTY; - } else if (unmoveStuff.redoStack.length > 0) { - dirtyState = CLEAN_WITH_REDO; - } else { - dirtyState = CLEAN_NO_TIMELINES; - } - - var saveLevelButton = document.getElementById("saveLevelButton"); - // the save button clears your timelines - saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; - if (dirtyState >= EDITOR_DIRTY) { - // you should save - saveLevelButton.classList.add("click-me"); - } else { - saveLevelButton.classList.remove("click-me"); - } - - var saveProgressButton = document.getElementById("saveProgressButton"); - // you can't save a replay if your level is dirty - if (dirtyState === CLEAN_WITH_REDO) { - saveProgressButton.textContent = "Forget Progress"; - } else { - saveProgressButton.textContent = "Save Progress"; - } - saveProgressButton.disabled = dirtyState >= EDITOR_DIRTY || dirtyState === CLEAN_NO_TIMELINES; -} -function haveCheatcodesBeenUsed() { - return !unmoveStuff.undoStack.every(function(changeLog) { - // normal movement always starts with "i". - return changeLog[0][0] === "i"; - }); -} - -var persistentState = { - showEditor: false, - showGrid: false, -}; -function savePersistentState() { - localStorage.snakefall = JSON.stringify(persistentState); -} -function loadPersistentState() { - try { - persistentState = JSON.parse(localStorage.snakefall); - } catch (e) { - } - persistentState.showEditor = !!persistentState.showEditor; - persistentState.showGrid = !!persistentState.showGrid; - showEditorChanged(); -} -var isGravityEnabled = true; -function isGravity() { - return isGravityEnabled || !persistentState.showEditor; -} -var isCollisionEnabled = true; -function isCollision() { - return isCollisionEnabled || !persistentState.showEditor; -} -function isAnyCheatcodeEnabled() { - return persistentState.showEditor && ( - !isGravityEnabled || !isCollisionEnabled - ); -} -var themeName = "Spring"; //Gooby -var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle, experimentalColors; -var curlyOutline = false; - -var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; -var bg2 = "rgba(254, 198, 145 * rgba(255, 192, 133"; -var bg3 = "rgba(145, 254, 198 * rgba(117, 255, 192"; -var bg4 = "rgba(7, 7, 83 * rgba(0, 0, 70"; - -var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; -var snakeColors2 = ["#f00", "#0f0", "#00f", "#ff0"]; -var snakeColors3 = ["#BA145C", "#E91624", "#F75802", "#FEFE28"]; - -var fruitColors1 = ["#ff0066","#ff36a6","#ff6b1f","#ff9900","#ff2600"]; -var fruitColors2 = ["black","black","black","black","black"]; - -var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spike, support, box, bolt -var spikeColors2 = ["gray", "black", "white", "black"]; -var spikeColors3 = ["#333", "#333", "#333", "#777"]; - -var blockColors1 = [ - ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"], - ["#853641","#963c84","#753d88","#5d3a96","#3a3990"] -]; -var blockColors2 = [ - ["#999"], - ["#999"] -]; -var blockColors3 = [ - ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"], - ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] -]; -var blockColors4 = [ - ["#150612", "#a52e8b", "#990077", "#d917af", "#4d003c"], - ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] -]; - -var fontSize = tileSize*5; -var textStyle1 = ["" + fontSize + "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose -var textStyle2 = ["" + fontSize + "px Impact", "#5702c6", "#ff0098"]; -var textStyle3 = ["" + fontSize + "px Impact", "#BA145C", "#F75802"]; -var textStyle4 = ["" + fontSize + "px Impact", "#ff0", "#f00"]; - -var experimentalColors1 = ["white", "#ffccff"]; -var experimentalColors2 = ["white", "#FEFE28"]; - -var themeCounter = 0; - -var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor, textStyle, experimentalColors - //["sky",], - ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], - ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], - ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], - ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] -]; - - -function showEditorChanged() { - document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; - ["editorDiv", "editorPane"].forEach(function(id) { - document.getElementById(id).style.display = persistentState.showEditor ? "block" : "none"; - }); - document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : "/WASD"; - - render(); -} - -function move(dr, dc) { - if (!isAlive()) return; - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; - animationStart = new Date().getTime(); - var activeSnake = findActiveSnake(); - var headRowcol = getRowcol(level, activeSnake.locations[0]); - var newRowcol = {r:headRowcol.r + dr, c:headRowcol.c + dc}; - if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; - var newLocation = getLocation(level, newRowcol.r, newRowcol.c); - var changeLog = []; - - // The changeLog for a player movement starts with the input - // when playing normally. - if (!isAnyCheatcodeEnabled()) { - changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); - } - - var ate = false; - var pushedObjects = []; - - //track ClosedLifts that had objects on them - var occupiedClosedLift = getOccupiedClosedLiftLocations(); - - if (isCollision()) { - var newTile = level.map[newLocation]; - if (newTile === BUBBLE || newTile === CLOUD) - paintTileAtLocation(newLocation, SPACE, changeLog); - else if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile - var otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { - if (otherObject === activeSnake) return; // can't push yourself - if (otherObject.type === FRUIT) { - // eat - removeObject(otherObject, changeLog); - ate = true; - } else if (isTileCodeAir(activeSnake, null, newTile, dr, dc)) { - otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { - if (otherObject === activeSnake) return; // can't push yourself - // push objects - if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; - } - } else return; // can't go through that tile - } - } - - // slither forward - var activeSnakeOldState = serializeObjectState(activeSnake); - var size1 = activeSnake.locations.length === 1; - var slitherAnimations = [ - 70, - [ - // size-1 snakes really do more of a move than a slither - size1 ? MOVE_SNAKE : SLITHER_HEAD, - activeSnake.id, - dr, - dc, - ] - ]; - activeSnake.locations.unshift(newLocation); - if (!ate) { - for(var i = 1; i 0) { - var anySnakesDied = false; - dyingObjects.forEach(function(object) { - if (object.type === SNAKE) { - // look what you've done - var oldState = serializeObjectState(object); - object.dead = true; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - anySnakesDied = true; - } else if (object.type === BLOCK) { - // a box fell off the world - removeAnimatedObject(object, changeLog); - removeFromArray(fallingObjects, object); - exitAnimationQueue.push([ - 200, - [ - DIE_BLOCK, - object.id, - 0, 0 - ], - ]); - didAnything = true; - } else throw unreachable(); - }); - if (anySnakesDied) break; - } - if (fallingObjects.length > 0) { - moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); - didAnything = true; - } - - occupiedClosedLift = openLift(occupiedClosedLift, changeLog); - - if (!didAnything) break; - Array.prototype.push.apply(animationQueue, exitAnimationQueue); - if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); - } - - pushUndo(unmoveStuff, changeLog); - render(); -} - -function combineOldAndNewLiftOccupations(oldOccupiedClosedLift) -{ - var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); - var newlyOccupiedClosedLift = getSetSubtract(newOccupiedClosedLift, oldOccupiedClosedLift); - return oldOccupiedClosedLift.concat(newlyOccupiedClosedLift); -} - -function openLift(oldOccupiedClosedLift, changeLog) -{ - var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); - var nowUnoccupiedClosedLift = getSetSubtract(oldOccupiedClosedLift, newOccupiedClosedLift); - for (var i = 0; i < nowUnoccupiedClosedLift.length; i++) { - paintTileAtLocation(nowUnoccupiedClosedLift[i], OPENLIFT, changeLog); - } - return newOccupiedClosedLift; -} - -function getSetSubtract(array1, array2) { - if (array1.length === 0) return []; - return array1.filter(function(x) { return array2.indexOf(x) == -1; }); -} - -function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects) { - // pusher can be null (for gravity) - pushedObjects.push(pushedObject); - // find forward locations - var forwardLocations = []; - for (var i = 0; i < pushedObjects.length; i++) { - pushedObject = pushedObjects[i]; - for (var j = 0; j < pushedObject.locations.length; j++) { - var rowcol = getRowcol(level, pushedObject.locations[j]); - var forwardRowcol = {r:rowcol.r + dr, c:rowcol.c + dc}; - if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { - if (dyingObjects == null) { - // can't push things out of bounds - return false; - } else { - // this thing is going to fall out of bounds - addIfNotPresent(dyingObjects, pushedObject); - addIfNotPresent(pushedObjects, pushedObject); - continue; - } - } - var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); - if (dr === 1 && level.map[forwardLocation] === PLATFORM) { - // this platform holds us, unless we're going through it - var neighborLocations; - if (pushedObject.type === SNAKE) { - neighborLocations = []; - if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); - if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); - } else if (pushedObject.type === BLOCK) { - neighborLocations = pushedObject.locations; - } else throw asdf; - if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface - // we slip right past it - } - var yetAnotherObject = findObjectAtLocation(forwardLocation); - if (yetAnotherObject != null) { - if (yetAnotherObject.type === FRUIT) { - // not pushable - return false; - } - if (yetAnotherObject === pusher) { - // indirect pushing ourselves. - // special check for when we're indirectly pushing the tip of our own tail. - if (forwardLocation === pusher.locations[pusher.locations.length -1]) { - // for some reason this is ok. ------------ THIS IS THE TAIL GLITCH - continue; - } - return false; - } - addIfNotPresent(pushedObjects, yetAnotherObject); - if(level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work - } else - addIfNotPresent(forwardLocations, forwardLocation); - } - } - // check forward locations - for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform, saw no effect but left new code - var forwardLocation = forwardLocations[i]; - // many of these locations can be inside objects, - // but that means the tile must be air, - // and we already know pushing that object. - var tileCode = level.map[forwardLocation]; - var object = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); - if (!isTileCodeAir(pusher, object, tileCode, dr, dc)) { - if (dyingObjects != null) { - if (tileCode === SPIKE) { - // uh... which object was this again? - if (object.type === SNAKE) { - // ouch! - addIfNotPresent(dyingObjects, object); - continue; - } - - } - else if (tileCode === LAVA) { - if (object.type === SNAKE || object.type === BLOCK) { - addIfNotPresent(dyingObjects, object); - continue; - } - } - else if (tileCode === WATER) { - if (object.type === BLOCK) { - addIfNotPresent(dyingObjects, object); - continue; - } - } - // can't push into something solid - return false; - } - } - } - // the push is go - return true; -} - -function activateAnySnakePlease() { - var snakes = getSnakes(); - if (snakes.length === 0) return; // nope.avi - activeSnakeId = snakes[0].id; -} - -function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations, changeLog, animations) { - objects.forEach(function(object) { - var oldState = serializeObjectState(object); - var oldPortals = getSetIntersection(portalLocations, object.locations); - for (var i = 0; i < object.locations.length; i++) { - object.locations[i] = offsetLocation(object.locations[i], dr, dc); - if (level.map[object.locations[i]] == BUBBLE || level.map[object.locations[i]] == CLOUD) - paintTileAtLocation(object.locations[i], SPACE, changeLog); - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - animations.push([ - "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK - object.id, - dr, - dc, - ]); - - var newPortals = getSetIntersection(portalLocations, object.locations); - var activatingPortals = newPortals.filter(function(portalLocation) { - return oldPortals.indexOf(portalLocation) === -1; - }); - if (activatingPortals.length === 1) { - // exactly one new portal we're touching. activate it - portalActivationLocations.push(activatingPortals[0]); - } - }); -} - -function activatePortal(portalLocations, portalLocation, animations, changeLog) { - var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; - var portalRowcol = getRowcol(level, portalLocation); - var otherPortalRowcol = getRowcol(level, otherPortalLocation); - var delta = {r:otherPortalRowcol.r - portalRowcol.r, c:otherPortalRowcol.c - portalRowcol.c}; - - var object = findObjectAtLocation(portalLocation); - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r + delta.r; - var c = rowcol.c + delta.c; - if (!isInBounds(level, r, c)) return false; // out of bounds - newLocations.push(getLocation(level, r, c)); - } - - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile - var otherObject = findObjectAtLocation(location); - if (otherObject != null && otherObject !== object) return; // blocked by object - } - - // zappo presto! - var oldState = serializeObjectState(object); - object.locations = newLocations; - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (level.map[location] == BUBBLE || level.map[location] == CLOUD) //changed this despite bubble working perfectly without it - paintTileAtLocation(location, SPACE, changeLog); - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); -} - -function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { - switch (tileCode) - { - case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; - case WOODPLATFORM: case BUBBLE: return pusher != null; - case PLATFORM: return dr != 1; - case ONEWAYWALLU: return dr != 1; - case ONEWAYWALLD: return dr != -1; - case ONEWAYWALLL: return dc != 1; - case ONEWAYWALLR: return dc != -1; - default: return false; - } -} - -function addIfNotPresent(array, element) { - if (array.indexOf(element) !== -1) return; - array.push(element); -} -function removeAnyObjectAtLocation(location, changeLog) { - var object = findObjectAtLocation(location); - if (object != null) removeObject(object, changeLog); -} -function removeAnimatedObject(object, changeLog) { - removeObject(object, changeLog); - freshlyRemovedAnimatedObjects.push(object); -} -function removeObject(object, changeLog) { - removeFromArray(level.objects, object); - changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0,[]]]); - if (object.type === SNAKE && object.id === activeSnakeId) { - activateAnySnakePlease(); - } - if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { - // no longer editing an object that doesn't exit - paintBrushBlockId = null; - } - if (object.type === BLOCK) { - delete blockSupportRenderCache[object.id]; - } -} -function removeFromArray(array, element) { - var index = array.indexOf(element); - if (index === -1) throw unreachable(); - array.splice(index, 1); -} -function findActiveSnake() { - var snakes = getSnakes(); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) return snakes[i]; - } - throw unreachable(); -} -function findBlockById(id) { - return findObjectOfTypeAndId(BLOCK, id); -} -function findSnakesOfColor(color) { - return level.objects.filter(function(object) { - if (object.type !== SNAKE) return false; - return object.id % snakeColors.length === color; - }); -} -function findObjectOfTypeAndId(type, id) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.type === type && object.id === id) return object; - } - return null; -} -function findObjectAtLocation(location) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.locations.indexOf(location) !== -1) - return object; - } - return null; -} -function isUneatenFruit() { - return getObjectsOfType(FRUIT).length > 0; -} -function getActivePortalLocations() { - var portalLocations = getPortalLocations(); - if (portalLocations.length !== 2) return []; // nice try - return portalLocations; -} -function getPortalLocations() { - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === PORTAL) result.push(i); - } - return result; -} -function countSnakes() { - return getSnakes().length; -} -function getSnakes() { - return getObjectsOfType(SNAKE); -} -function getBlocks() { - return getObjectsOfType(BLOCK); -} -function getOccupiedClosedLiftLocations() -{ - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === CLOSEDLIFT) { - if (findObjectAtLocation(i)) - result.push(i); - } - } - return result; -} -function getObjectsOfType(type) { - return level.objects.filter(function(object) { - return object.type == type; - }); -} -function isDead() { - if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; - return getSnakes().filter(function(snake) { - return !!snake.dead; - }).length > 0; -} -function isAlive() { - return countSnakes() > 0 && !isDead(); -} - -var activeSnakeId = null; - -var SLITHER_HEAD = "sh"; -var SLITHER_TAIL = "st"; -var MOVE_SNAKE = "ms"; -var MOVE_BLOCK = "mb"; -var TELEPORT_SNAKE = "ts"; -var TELEPORT_BLOCK = "tb"; -var EXIT_SNAKE = "es"; -var DIE_SNAKE = "ds"; -var DIE_BLOCK = "db"; -var INFINITE_LOOP = "il"; -var animationQueue = [ - // // sequence of disjoint animation groups. - // // each group completes before the next begins. - // [ - // 70, // duration of this animation group - // // multiple things to animate simultaneously - // [ - // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, - // objectId, - // dr, - // dc, - // ], - // [ - // INFINITE_LOOP, - // loopSizeNotIncludingThis, - // ], - // ], -]; -var animationQueueCursor = 0; -var animationStart = null; // new Date().getTime() -var animationProgress; // 0.0 <= x < 1.0 -var freshlyRemovedAnimatedObjects = []; - -// render the support beams for blocks into a temporary buffer, and remember it. -// this is due to stencil buffers causing slowdown on some platforms. see #25. -var blockSupportRenderCache = { - // id: canvas, - // "0": document.createElement("canvas"), -}; - -function render() { - if (level == null) return; - if (animationQueueCursor < animationQueue.length) { - var animationDuration = animationQueue[animationQueueCursor][0]; - animationProgress = (new Date().getTime() - animationStart) / animationDuration; - if (animationProgress >= 1.0) { - // animation group complete - animationProgress -= 1.0; - animationQueueCursor++; - if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { - var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; - animationQueueCursor -= infiniteLoopSize; - } - animationStart = new Date().getTime(); - } - } - if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; - canvas.width = tileSize * level.width; - canvas.height = tileSize * level.height; - var context = canvas.getContext("2d"); //Gooby - - themeName = themes[themeCounter][0]; - if(themeName!="sky"){ - background = themes[themeCounter][1]; - material = themes[themeCounter][2]; - surface = themes[themeCounter][3]; - curlyOutline = themes[themeCounter][4]; - snakeColors = themes[themeCounter][5]; - blockColors = themes[themeCounter][6]; - spikeColors = themes[themeCounter][7]; - fruitColors = themes[themeCounter][8]; - textStyle = themes[themeCounter][10]; - experimentalColors = themes[themeCounter][11]; + + + Snakefall + + + + + + + + +
    +
    + +
    + +
    +
    +
    + +
    Snakefall Redesign
    + +
    Show Hidden Options
    Most checkmarks contain links to solutions, though some are not accessible without a password.
    +
    + +
    Standard Puzzles
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SolutionLevelCreatorNote
    Disabilities Actthejoshwolfe
    Crashing Downthejoshwolfe
    Etch-a-sketchinukoblainc
    Fruit FallXeroOl
    Block ValleyXeroOl
    Block Valley 2XeroOl
    Spike MazeXeroOl
    Fruit MazeXeroOl
    Box BridgeXeroOl
    Please add animationsXeroOl
    The Ordealthejoshwolfe
    Coral BlockXeroOl
    AdventureXeroOl
    Sky GridXeroOl
    Block TrainXeroOl
    Turn AroundXeroOl
    Turn Around 2XeroOl
    There and Back Againgavinksong
    You Don't Have To Wait For Animationsthejoshwolfe
    KeyholeXeroOl
    Block Train 2XeroOl
    Fruit Maze 2XeroOl
    Tight SpaceXeroOl
    Floating FruitsXeroOl
    SkyscraperXeroOl
    Fruit Maze 3XeroOl
    Fruit Maze 4XeroOl
    Fruit Maze 5XeroOl
    Fruit Maze 6XeroOl
    DisarmXeroOl
    Level 1DoctorEndugu
    Level 2DoctorEndugu
    Bumpy RoadXeroOl
    Level 0 "Checkmark Underpass"Teal Knight
    Level 1 "Hanging spikes"Teal Knight
    Level 2 "Trap Mine"Teal Knight
    Level 3 "The Servant"Teal Knight
    Level 4 "Greed that goes well"Teal Knight
    Level 5 "Collapse"Teal Knight
    Level 6 "Decisions"Teal Knight
    Level 1Cookie
    Level 2Cookie
    Level 3Cookie
    Level 3 2Joel FoxDerived from Cookie's level above
    Balancing ActIHNN
    TempleJoel Fox
    Renovated TempleJoel FoxAddresses a common criticism of Temple
    BasilicaGoobyBased on Joel's levels above
    The BirdcageGooby
    The Birds UncagedJoel FoxDerived from Gooby's level above
    StrippedGoobyBased on The Birdcage and The Birds Uncaged
    SerpentineCollaborationCreated by Gooby & Joel Fox
    The SawmillGooby
    The HardmillJoel FoxDerived from Gooby's level above
    Mine RescueGoobyAllow time for solution to load
    Fruit TempleXeroI0I'm sorry
    Plane CrashGoobyNovelty Guess-the-Exit Special
    Top ShelfGooby
    Top Shelf 2Gooby
    PlinkoGooby
    The Puppet MasterGooby
    Rainbow BridgeGooby
    CastleGooby
    PerchGooby
    Black MambaGooby
    +
    +
    + +
    Experimental Puzzles
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SolutionLevelCreatorNote
    Under CoverXeroOl
    Snake FilterXeroOl
    Platformway to Heaventhejoshwolfe
    Under Cover 2XeroOl
    Low ClearanceXeroOl
    Baited TrapXeroOl
    Gateway to FreedomLevelWorld
    House on FireGooby
    UndergroundGooby
    BundókGooby
    +
    +
    + +
    nohatcoder Puzzles
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SolutionLevelCreatorNote
    Fruity Gapnohatcoder
    Bridgenohatcoder
    Abyssnohatcoder
    Tubenohatcoder
    Tunnelnohatcoder
    Transportedderiofer, nohatcoder, & Gooby
    +
    +
    + +
    Avis Anguis Puzzles
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SolutionLevelCreatorNote
    DemoTerzalo
    Level AConnorses
    Level BConnorses
    Level 1CHz
    Level 2CHz
    Level 3CHz
    +
    +
    + +
    Gameboy Puzzles
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    SolutionLevelCreatorNote
    Level 1freeball1
    Level 2freeball1
    Level 3freeball1
    Level 4freeball1
    Level 5freeball1
    Level 6freeball1
    Level 7freeball1
    Level 8freeball1
    Level 9freeball1
    Level 10freeball1
    +
    +
    + + + + + From aeee9ad3d39267a0f64ba37e5487e9afd73b6c37 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 22:14:53 -0500 Subject: [PATCH 267/577] Update index.html --- index.html | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/index.html b/index.html index c303ef7d..d42872c9 100644 --- a/index.html +++ b/index.html @@ -506,42 +506,42 @@ - Under Cover + Under Cover XeroOl - Snake Filter + Snake Filter XeroOl - Platformway to Heaven + Platformway to Heaven thejoshwolfe - Under Cover 2 + Under Cover 2 XeroOl - Low Clearance + Low Clearance XeroOl - Baited Trap + Baited Trap XeroOl @@ -555,21 +555,21 @@ - House on Fire + House on Fire Gooby - Underground + Underground Gooby - Bundók + Bundók Gooby From c88b1e8b05d06c3e42f8cd0f00fb9182976cf5ad Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 22:15:04 -0500 Subject: [PATCH 268/577] Update Main.js --- Main.js | 5125 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 4304 insertions(+), 821 deletions(-) diff --git a/Main.js b/Main.js index a858ef24..3a31525e 100644 --- a/Main.js +++ b/Main.js @@ -1,827 +1,4310 @@ - - - Snakefall - - - - - - - - -
    -
    - -
    - -
    -
    -
    - -
    Snakefall Redesign
    - -
    Show Hidden Options
    Most checkmarks contain links to solutions, though some are not accessible without a password.
    -
    - -
    Standard Puzzles
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SolutionLevelCreatorNote
    Disabilities Actthejoshwolfe
    Crashing Downthejoshwolfe
    Etch-a-sketchinukoblainc
    Fruit FallXeroOl
    Block ValleyXeroOl
    Block Valley 2XeroOl
    Spike MazeXeroOl
    Fruit MazeXeroOl
    Box BridgeXeroOl
    Please add animationsXeroOl
    The Ordealthejoshwolfe
    Coral BlockXeroOl
    AdventureXeroOl
    Sky GridXeroOl
    Block TrainXeroOl
    Turn AroundXeroOl
    Turn Around 2XeroOl
    There and Back Againgavinksong
    You Don't Have To Wait For Animationsthejoshwolfe
    KeyholeXeroOl
    Block Train 2XeroOl
    Fruit Maze 2XeroOl
    Tight SpaceXeroOl
    Floating FruitsXeroOl
    SkyscraperXeroOl
    Fruit Maze 3XeroOl
    Fruit Maze 4XeroOl
    Fruit Maze 5XeroOl
    Fruit Maze 6XeroOl
    DisarmXeroOl
    Level 1DoctorEndugu
    Level 2DoctorEndugu
    Bumpy RoadXeroOl
    Level 0 "Checkmark Underpass"Teal Knight
    Level 1 "Hanging spikes"Teal Knight
    Level 2 "Trap Mine"Teal Knight
    Level 3 "The Servant"Teal Knight
    Level 4 "Greed that goes well"Teal Knight
    Level 5 "Collapse"Teal Knight
    Level 6 "Decisions"Teal Knight
    Level 1Cookie
    Level 2Cookie
    Level 3Cookie
    Level 3 2Joel FoxDerived from Cookie's level above
    Balancing ActIHNN
    TempleJoel Fox
    Renovated TempleJoel FoxAddresses a common criticism of Temple
    BasilicaGoobyBased on Joel's levels above
    The BirdcageGooby
    The Birds UncagedJoel FoxDerived from Gooby's level above
    StrippedGoobyBased on The Birdcage and The Birds Uncaged
    SerpentineCollaborationCreated by Gooby & Joel Fox
    The SawmillGooby
    The HardmillJoel FoxDerived from Gooby's level above
    Mine RescueGoobyAllow time for solution to load
    Fruit TempleXeroI0I'm sorry
    Plane CrashGoobyNovelty Guess-the-Exit Special
    Top ShelfGooby
    Top Shelf 2Gooby
    PlinkoGooby
    The Puppet MasterGooby
    Rainbow BridgeGooby
    CastleGooby
    PerchGooby
    Black MambaGooby
    -
    -
    - -
    Experimental Puzzles
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SolutionLevelCreatorNote
    Under CoverXeroOl
    Snake FilterXeroOl
    Platformway to Heaventhejoshwolfe
    Under Cover 2XeroOl
    Low ClearanceXeroOl
    Baited TrapXeroOl
    Gateway to FreedomLevelWorld
    House on FireGooby
    UndergroundGooby
    BundókGooby
    -
    -
    - -
    nohatcoder Puzzles
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SolutionLevelCreatorNote
    Fruity Gapnohatcoder
    Bridgenohatcoder
    Abyssnohatcoder
    Tubenohatcoder
    Tunnelnohatcoder
    Transportedderiofer, nohatcoder, & Gooby
    -
    -
    - -
    Avis Anguis Puzzles
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SolutionLevelCreatorNote
    DemoTerzalo
    Level AConnorses
    Level BConnorses
    Level 1CHz
    Level 2CHz
    Level 3CHz
    -
    -
    - -
    Gameboy Puzzles
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    SolutionLevelCreatorNote
    Level 1freeball1
    Level 2freeball1
    Level 3freeball1
    Level 4freeball1
    Level 5freeball1
    Level 6freeball1
    Level 7freeball1
    Level 8freeball1
    Level 9freeball1
    Level 10freeball1
    -
    -
    - - - - - + // just skip it + continue; + } + var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); + newLocations.push(newLocation); + } + if (newLocations.length === 0) return; // can't have a non-present object + var newObject = JSON.parse(JSON.stringify(object)); + newObject.locations = newLocations; + selectedObjects.push(newObject); + }); + return { + level: newLevel, + selectedLocations: selectedLocations, + selectedObjects: selectedObjects, + }; +} + +function getNaiveOrthogonalPath(a, b) { + // does not include a, but does include b. + var rowcolA = getRowcol(level, a); + var rowcolB = getRowcol(level, b); + var path = []; + if (rowcolA.r < rowcolB.r) { + for (var r = rowcolA.r; r < rowcolB.r; r++) { + path.push(getLocation(level, r + 1, rowcolA.c)); + } + } else { + for (var r = rowcolA.r; r > rowcolB.r; r--) { + path.push(getLocation(level, r - 1, rowcolA.c)); + } + } + if (rowcolA.c < rowcolB.c) { + for (var c = rowcolA.c; c < rowcolB.c; c++) { + path.push(getLocation(level, rowcolB.r, c + 1)); + } + } else { + for (var c = rowcolA.c; c > rowcolB.c; c--) { + path.push(getLocation(level, rowcolB.r, c - 1)); + } + } + return path; +} +function identityFunction(x) { + return x; +} +function compareId(a, b) { + return operatorCompare(a.id, b.id); +} +function operatorCompare(a, b) { + return a < b ? -1 : a > b ? 1 : 0; +} +function clamp(value, min, max) { + if (value < min) return min; + if (value > max) return max; + return value; +} +function copyArray(array) { + return array.map(identityFunction); +} +function getSetIntersection(array1, array2) { + if (array1.length * array2.length === 0) return []; + return array1.filter(function(x) { return array2.indexOf(x) !== -1; }); +} +function makeScaleCoordinatesFunction(width1, width2) { + return function(location) { + return location + (width2 - width1) * Math.floor(location / width1); + }; +} + +var expectHash; +window.addEventListener("hashchange", function() { + if (location.hash === expectHash) { + // We're in the middle of saveLevel() or saveReplay(). + // Don't react to that event. + expectHash = null; + return; + } + // The user typed into the url bar or used Back/Forward browser buttons, etc. + loadFromLocationHash(); +}); +function loadFromLocationHash() { + var hashSegments = location.hash.split("#"); + hashSegments.shift(); // first element is always "" + if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; + var hashPairs = hashSegments.map(function(segment) { + var equalsIndex = segment.indexOf("="); + if (equalsIndex === -1) return ["", segment]; // bad + return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; + }); + + if (hashPairs[0][0] !== "level") return false; + try { + var level = parseLevel(hashPairs[0][1]); + } catch (e) { + alert(e); + return false; + } + loadLevel(level); + if (hashPairs.length > 1) { + try { + if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); + parseAndLoadReplay(hashPairs[1][1]); + } catch (e) { + alert(e); + return false; + } + } + return true; +} + +// run test suite +var testTime = new Date().getTime(); +if (compressSerialization(stringifyLevel(parseLevel(testLevel_v0))) !== testLevel_v0_converted) throw new Error("v0 level conversion is broken"); +// ask the debug console for this variable if you're concerned with how much time this wastes. +testTime = new Date().getTime() - testTime; + +loadPersistentState(); +if (!loadFromLocationHash()) { + loadLevel(parseLevel(exampleLevel)); +} From 8ab6e9219e814b0ef98c20e61b1949a742766a59 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 22:18:03 -0500 Subject: [PATCH 269/577] Update Main.js --- Main.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Main.js b/Main.js index 3a31525e..07945b21 100644 --- a/Main.js +++ b/Main.js @@ -2980,6 +2980,7 @@ function drawLiquid(r, c, type, adjacentTiles) { } function newLiquid(r, c, type, isOccupied){ + context.save(); var tubColor; if(type == LAVA) { context.fillStyle = "#ffbf00"; @@ -3021,6 +3022,7 @@ function newLiquid(r, c, type, isOccupied){ else if(isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); else roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize, tileSize*.2, 0, true, false); } + context.restore(); } function drawLift(r, c, isFixed) { From 4bdf700261c095575d4d85e33043364a67175228 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 22:20:43 -0500 Subject: [PATCH 270/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index b598a5f1..98a89d21 100644 --- a/Framework.html +++ b/Framework.html @@ -15,7 +15,7 @@ ← Snakefall Redesign - + Edits: 0+0 From 62ae9a0f9cf44fe60da7a94464325ba11868d43c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 22:24:19 -0500 Subject: [PATCH 271/577] Update Main.js --- Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.js b/Main.js index 07945b21..6aeba77a 100644 --- a/Main.js +++ b/Main.js @@ -741,7 +741,7 @@ document.getElementById("themeButton").addEventListener("click", function() { function toggleTheme() { if(themeCounter"; } From 4d69d07701449328c6e697c6b80bc57b1418bae1 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 23:35:46 -0500 Subject: [PATCH 272/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index d42872c9..3099b29d 100644 --- a/index.html +++ b/index.html @@ -562,7 +562,7 @@ - Underground + Underground Gooby From e6636b949d5d591fa40d69a58bc76591ba12154f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 23:52:53 -0500 Subject: [PATCH 273/577] Update Main.js --- Main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Main.js b/Main.js index 6aeba77a..53b5ed98 100644 --- a/Main.js +++ b/Main.js @@ -1787,7 +1787,7 @@ function move(dr, dc) { // push objects if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; } - } else return; // can't go through that tile + } else return; // can't go through that tile } } @@ -2044,9 +2044,9 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects continue; } } - // can't push into something solid - return false; } + // can't push into something solid + return false; } } // the push is go From 9e7bf35b6a9f5f01f3af88b6dcac2b558913aadc Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 17 Feb 2020 23:59:04 -0500 Subject: [PATCH 274/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index 98a89d21..3755e684 100644 --- a/Framework.html +++ b/Framework.html @@ -40,7 +40,7 @@ Experimental Elements Removeables - + Scissor Lifts From 3c2e580514db9f59db02a1bd4b4e07745beeedaf Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 18 Feb 2020 17:06:39 -0500 Subject: [PATCH 275/577] Update Framework.html --- Framework.html | 1 + 1 file changed, 1 insertion(+) diff --git a/Framework.html b/Framework.html index 3755e684..e81db58b 100644 --- a/Framework.html +++ b/Framework.html @@ -74,6 +74,7 @@ +
    From edf458542a3d066bcdafee903d3589764faec1b1 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 18 Feb 2020 17:07:07 -0500 Subject: [PATCH 276/577] Create SolutionVerification --- SolutionVerification | 48 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 SolutionVerification diff --git a/SolutionVerification b/SolutionVerification new file mode 100644 index 00000000..96f31d8a --- /dev/null +++ b/SolutionVerification @@ -0,0 +1,48 @@ + + + Snakefall Redesign + + + + + + + + + + +
    + +
    +
    + + + +
    + + + + + + + + From eb4e42d1fe6819e9a34e4cf59388f6bcbb26b44b Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 18 Feb 2020 17:08:00 -0500 Subject: [PATCH 277/577] Update Main.js --- Main.js | 131 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 94 insertions(+), 37 deletions(-) diff --git a/Main.js b/Main.js index 53b5ed98..ea1d39a8 100644 --- a/Main.js +++ b/Main.js @@ -44,6 +44,9 @@ var FRUIT = "f"; var headRowMove; var headColMove; +var checkResult = false; +var cr = false; +var cs = false; var tileSize = 34; var level; @@ -622,6 +625,9 @@ document.getElementById("showGridButton").addEventListener("click", function() { document.getElementById("saveProgressButton").addEventListener("click", function() { saveReplay(); }); +document.getElementById("checkSolutionButton").addEventListener("click", function() { + redoAll(unmoveStuff); +}); document.getElementById("restartButton").addEventListener("click", function() { reset(unmoveStuff); render(); @@ -1409,6 +1415,30 @@ function redo(undoStuff) { redoOneFrame(undoStuff); undoStuffChanged(undoStuff); } +function redoAll(undoStuff) { + if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); + // preserve the level in the url bar. + var hash = "#level=" + currentSerializedLevel; + if (dirtyState === REPLAY_DIRTY) { + // there is a replay to save + hash += "#replay=" + compressSerialization(stringifyReplay()); + } + + var sv = "https://jmdiamond3.github.io/Snakefall-Redesign/SolutionVerification.html" + hash; + copyToClipboard(sv); +} +function copyToClipboard(text) { + var dummy = document.createElement("textarea"); + // to avoid breaking orgain page when copying more words + // cant copy when adding below this code + // dummy.style.display = 'none' + document.body.appendChild(dummy); + //Be careful if you use texarea. setAttribute('value', value), which works with "input" does not work with "textarea". – Eduard + dummy.value = text; + dummy.select(); + document.execCommand("copy"); + document.body.removeChild(dummy); +} function unreset(undoStuff) { animationQueue = []; animationQueueCursor = 0; @@ -2461,49 +2491,51 @@ function render() { context.drawImage(image, c * tileSize, r * tileSize); }); - // terrain - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - var tileCode = level.map[location]; - drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids + if(!cs) { + // terrain + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + var tileCode = level.map[location]; + drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids + } + } } - } - } - - for(var i = 0; i Date: Tue, 18 Feb 2020 17:08:17 -0500 Subject: [PATCH 278/577] Create SV.js --- SV.js | 4096 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 4096 insertions(+) create mode 100644 SV.js diff --git a/SV.js b/SV.js new file mode 100644 index 00000000..3c3feed8 --- /dev/null +++ b/SV.js @@ -0,0 +1,4096 @@ +function unreachable() { return new Error("unreachable"); } +if (typeof VERSION !== "undefined") { + document.getElementById("versionSpan").innerHTML = + '' + VERSION.tag + ''; +} +/*$(document).ready(function() { + var fruits1 = getObjectsOfType(FRUIT); + $(fruits1[0]).jqFloat({ + width: 10, + height: 10, + speed: 100 + }); +});*/ + +var img3 = document.createElement('img'); //Gooby +//img3.src = '/Snakefall/Snakebird Images/Cherry2.png'; + +var canvas = document.getElementById("canvas"); + +var SPACE = "0".charCodeAt(0); +var WALL = "1".charCodeAt(0); +var SPIKE = "2".charCodeAt(0); +var FRUIT_v0 = "3".charCodeAt(0); //legacy +var EXIT = "4".charCodeAt(0); +var PORTAL = "5".charCodeAt(0); +var PLATFORM = "P".charCodeAt(0); +var WOODPLATFORM = "p".charCodeAt(0); +var ONEWAYWALLU = "u".charCodeAt(0); +var ONEWAYWALLD = "d".charCodeAt(0); +var ONEWAYWALLL = "l".charCodeAt(0); +var ONEWAYWALLR = "r".charCodeAt(0); +var CLOUD = "C".charCodeAt(0); +var BUBBLE = "b".charCodeAt(0); +var CLOSEDLIFT = "c".charCodeAt(0); +var OPENLIFT = "o".charCodeAt(0); +var LAVA = "v".charCodeAt(0); +var WATER = "w".charCodeAt(0); +var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, CLOSEDLIFT, OPENLIFT, CLOUD, BUBBLE, LAVA, WATER]; + +// object types +var SNAKE = "s"; +var BLOCK = "b"; +var FRUIT = "f"; + +var headRowMove; +var headColMove; +var checkResult = false; +var cr = false; +var cs = false; + +var tileSize = 34; +var level; +var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; +var uneditStuff = {undoStack:[], redoStack:[], spanId:"editsSpan", undoButtonId:"uneditButton", redoButtonId:"reeditButton"}; +var paradoxes = []; +function loadLevel(newLevel) { + level = newLevel; + currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); + + activateAnySnakePlease(); + unmoveStuff.undoStack = []; + unmoveStuff.redoStack = []; + undoStuffChanged(unmoveStuff); + uneditStuff.undoStack = []; + uneditStuff.redoStack = []; + undoStuffChanged(uneditStuff); + blockSupportRenderCache = {}; + render(); +} + + +var magicNumber_v0 = "3tFRIoTU"; +var magicNumber = "HyRr4JK1"; +var exampleLevel = magicNumber_v0 + "&" + + "17&31" + + "?" + + "0000000000000000000000000000000" + + "0000000000000000000000000000000" + + "0000000000000000000000000000000" + + "0000000000000000000000000000000" + + "0000000000000000000000000000000" + + "0000000000000000000000000000000" + + "0000000000000000000040000000000" + + "0000000000000110000000000000000" + + "0000000000000111100000000000000" + + "0000000000000011000000000000000" + + "0000000000000010000010000000000" + + "0000000000000010100011000000000" + + "0000001111111000110000000110000" + + "0000011111111111111111111110000" + + "0000011111111101111111111100000" + + "0000001111111100111111111100000" + + "0000001111111000111111111100000" + + "/" + + "s0 ?351&350&349/" + + "f0 ?328/" + + "f1 ?366/"; + +var testLevel_v0 = "3tFRIoTU&5&5?0005*00300024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/"; +var testLevel_v0_converted = "HyRr4JK1&5&5?0005*4024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/f0?8/"; + +function parseLevel(string) { + // magic number + var cursor = 0; + skipWhitespace(); + var versionTag = string.substr(cursor, magicNumber.length); + switch (versionTag) { + case magicNumber_v0: + case magicNumber: break; + default: throw new Error("not a snakefall level"); + } + cursor += magicNumber.length; + consumeKeyword("&"); + + var level = { + height: -1, + width: -1, + map: [], + objects: [], + }; + + // height, width + level.height = readInt(); + consumeKeyword("&"); + level.width = readInt(); + + // map + var mapData = readRun(); + mapData = decompressSerialization(mapData); + if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); + var upconvertedObjects = []; + var fruitCount = 0; + var tileCounter = 0; + for (var i = 0; i < mapData.length; i++) { + var tileCode = mapData[i].charCodeAt(0); + if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { + // fruit used to be a tile code. now it's an object. + upconvertedObjects.push({ + type: FRUIT, + id: fruitCount++, + dead: false, // unused + locations: [i], + }); + tileCode = SPACE; + } + if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; + if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); + level.map.push(tileCode); + } + + // objects + skipWhitespace(); + while (cursor < string.length) { + var object = { + type: "?", + id: -1, + dead: false, + locations: [], + }; + + // type + object.type = string[cursor]; + var locationsLimit; + if (object.type === SNAKE) locationsLimit = -1; + else if (object.type === BLOCK) locationsLimit = -1; + else if (object.type === FRUIT) locationsLimit = 1; + else throw parserError("expected object type code"); + cursor += 1; + + // id + object.id = readInt(); + + // locations + var locationsData = readRun(); + var locationStrings = locationsData.split("&"); + if (locationStrings.length === 0) throw parserError("locations must be non-empty"); + if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); + + locationStrings.forEach(function(locationString) { + var location = parseInt(locationString); + if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); + object.locations.push(location); + }); + + level.objects.push(object); + skipWhitespace(); + } + + for (var i = 0; i < upconvertedObjects.length; i++) { + level.objects.push(upconvertedObjects[i]); + } + + return level; + + function skipWhitespace() { + while (" \n\t\r".indexOf(string[cursor]) !== -1) { + cursor += 1; + } + } + function consumeKeyword(keyword) { + skipWhitespace(); + if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); + cursor += 1; + } + function readInt() { + skipWhitespace(); + for (var i = cursor; i < string.length; i++) { + if ("0123456789".indexOf(string[i]) === -1) break; + } + var substring = string.substring(cursor, i); + if (substring.length === 0) throw parserError("expected int"); + cursor = i; + return parseInt(substring, 10); + } + function readRun() { + consumeKeyword("?"); + var endIndex = string.indexOf("/", cursor); + var substring = string.substring(cursor, endIndex); + cursor = endIndex + 1; + return substring; + } + function parserError(message) { + return new Error("parse error at position " + cursor + ": " + message); + } +} + +function serializeTileCode(tileCode) { + return String.fromCharCode(tileCode); +} + +function stringifyLevel(level) { + var output = magicNumber + "&"; + output += level.height + "&" + level.width + "\n"; + + output += "?\n"; + for (var r = 0; r < level.height; r++) { + output += " " + level.map.slice(r * level.width, (r + 1) * level.width).map(serializeTileCode).join("") + "\n"; + } + output += "/\n"; + + output += serializeObjects(level.objects); + + // sanity check + var shouldBeTheSame = parseLevel(output); + if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken + + return output; +} +function serializeObjects(objects) { + var output = ""; + for (var i = 0; i < objects.length; i++) { + var object = objects[i]; + output += object.type + object.id + " "; + output += "?" + object.locations.join("&") + "/\n"; + } + return output; +} +function serializeObjectState(object) { + if (object == null) return [0,[]]; + return [object.dead, copyArray(object.locations)]; +} + +var base66 = "----0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; +function compressSerialization(string) { + string = string.replace(/\s+/g, ""); + // run-length encode several 0's in a row, etc. + // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) + var result = ""; + var runStart = 0; + for (var i = 1; i < string.length + 1; i++) { + var runLength = i - runStart; + if (string[i] === string[runStart] && runLength < base66.length - 1) continue; + // end of run + if (runLength >= 4) { + // compress + result += "*" + base66[runLength] + string[runStart]; + } else { + // literal + result += string.substring(runStart, i); + } + runStart = i; + } + return result; +} +function decompressSerialization(string) { + string = string.replace(/\s+/g, ""); + var result = ""; + for (var i = 0; i < string.length; i++) { + if (string[i] === "*") { + i += 1; + var runLength = base66.indexOf(string[i]); + i += 1; + var char = string[i]; + for (var j = 0; j < runLength; j++) { + result += char; + } + } else { + result += string[i]; + } + } + return result; +} + +var replayMagicNumber = "nmGTi8PB"; +function stringifyReplay() { + var output = replayMagicNumber + "&"; + // only specify the snake id in an input if it's different from the previous. + // the first snake index is 0 to optimize for the single-snake case. + var currentSnakeId = 0; + for (var i = 0; i < unmoveStuff.undoStack.length; i++) { + var firstChange = unmoveStuff.undoStack[i][0]; + if (firstChange[0] !== "i") throw unreachable(); + var snakeId = firstChange[1]; + var dr = firstChange[2]; + var dc = firstChange[3]; + var directionCode; + if (dr ===-1 && dc === 0) directionCode = "u"; + else if (dr === 0 && dc ===-1) directionCode = "l"; + else if (dr === 1 && dc === 0) directionCode = "d"; + else if (dr === 0 && dc === 1) directionCode = "r"; + else throw unreachable(); + if (snakeId !== currentSnakeId) { + output += snakeId; // int to string + currentSnakeId = snakeId; + } + output += directionCode; + } + return output; +} +function parseAndLoadReplay(string) { + string = decompressSerialization(string); + var expectedPrefix = replayMagicNumber + "&"; + if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); + var cursor = expectedPrefix.length; + + // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. + activeSnakeId = 0; + while (cursor < string.length) { + var snakeIdStr = ""; + var c = string.charAt(cursor); + cursor += 1; + while ('0' <= c && c <= '9') { + snakeIdStr += c; + if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); + c = string.charAt(cursor); + cursor += 1; + } + if (snakeIdStr.length > 0) { + activeSnakeId = parseInt(snakeIdStr); + // don't just validate when switching snakes, but on every move. + } + + // doing a move. + if (!getSnakes().some(function(snake) { + return snake.id === activeSnakeId; + })) { + throw new Error("invalid snake id: " + activeSnakeId); + } + switch (c) { + case 'l': move( 0, -1); break; + case 'u': move(-1, 0); break; + case 'r': move( 0, 1); break; + case 'd': move( 1, 0); break; + default: throw new Error("replay string has invalid direction: " + c); + } + } + + // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. + reset(unmoveStuff); + document.getElementById("removeButton").classList.add("click-me"); +} + +var currentSerializedLevel; +function saveLevel() { + if (isDead()) return alert("Can't save while you're dead!"); + var serializedLevel = compressSerialization(stringifyLevel(level)); + currentSerializedLevel = serializedLevel; + var hash = "#level=" + serializedLevel; + expectHash = hash; + location.hash = hash; + + // This marks a starting point for solving the level. + unmoveStuff.undoStack = []; + unmoveStuff.redoStack = []; + editorHasBeenTouched = false; + undoStuffChanged(unmoveStuff); +} + +function saveReplay() { + if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); + // preserve the level in the url bar. + var hash = "#level=" + currentSerializedLevel; + if (dirtyState === REPLAY_DIRTY) { + // there is a replay to save + hash += "#replay=" + compressSerialization(stringifyReplay()); + } + expectHash = hash; + location.hash = hash; +} + +function deepEquals(a, b) { + if (a == null) return b == null; + if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; + if (Array.isArray(a)) { + if (!Array.isArray(b)) return false; + if (a.length !== b.length) return false; + for (var i = 0; i < a.length; i++) { + if (!deepEquals(a[i], b[i])) return false; + } + return true; + } + // must be objects + var aKeys = Object.keys(a); + var bKeys = Object.keys(b); + if (aKeys.length !== bKeys.length) return false; + aKeys.sort(); + bKeys.sort(); + if (!deepEquals(aKeys, bKeys)) return false; + for (var i = 0; i < aKeys.length; i++) { + if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; + } + return true; +} + +function getLocation(level, r, c) { + if (!isInBounds(level, r, c)) throw unreachable(); + return r * level.width + c; +} +function getRowcol(level, location) { + if (location < 0 || location >= level.width * level.height) throw unreachable(); + var r = Math.floor(location / level.width); + var c = location % level.width; + return {r:r, c:c}; +} +function isInBounds(level, r, c) { + if (c < 0 || c >= level.width) return false;; + if (r < 0 || r >= level.height) return false;; + return true; +} +function offsetLocation(location, dr, dc) { + var rowcol = getRowcol(level, location); + return getLocation(level, rowcol.r + dr, rowcol.c + dc); +} + +document.getElementById("checkSolutionButton").addEventListener("click", function() { + redoAll(unmoveStuff); +}); +document.getElementById("unmoveButton").addEventListener("click", function() { + undo(unmoveStuff); + render(); +}); +document.getElementById("removeButton").addEventListener("click", function() { + redo(unmoveStuff); + render(); +}); + +["serializationTextarea", "shareLinkTextbox"].forEach(function(id) { + document.getElementById(id).addEventListener("keydown", function(event) { + // let things work normally + event.stopPropagation(); + }); +}); +document.getElementById("submitSerializationButton").addEventListener("click", function() { + var string = document.getElementById("serializationTextarea").value; + try { + var newLevel = parseLevel(string); + } catch (e) { + alert(e); + return; + } + loadLevel(newLevel); +}); +document.getElementById("shareLinkTextbox").addEventListener("focus", function() { + setTimeout(function() { + document.getElementById("shareLinkTextbox").select(); + }, 0); +}); + +var paintBrushTileCode = null; +var paintBrushSnakeColorIndex = 0; +var paintBrushBlockId = 0; +var paintBrushObject = null; +var selectionStart = null; +var selectionEnd = null; +var resizeDragAnchorRowcol = null; +var clipboardData = null; +var clipboardOffsetRowcol = null; +var paintButtonIdAndTileCodes = [ + ["resizeButton", "resize"], + ["selectButton", "select"], + ["pasteButton", "paste"], +]; +paintButtonIdAndTileCodes.forEach(function(pair) { + var id = pair[0]; + var tileCode = pair[1]; + document.getElementById(id).addEventListener("click", function() { + setPaintBrushTileCode(tileCode); + }); +}); +document.getElementById("uneditButton").addEventListener("click", function() { + undo(uneditStuff); + render(); +}); +document.getElementById("reeditButton").addEventListener("click", function() { + redo(uneditStuff); + render(); +}); +document.getElementById("saveLevelButton").addEventListener("click", function() { + saveLevel(); +}); +document.getElementById("copyButton").addEventListener("click", function() { + copySelection(); +}); +document.getElementById("cutButton").addEventListener("click", function() { + cutSelection(); +}); + +// be careful with location vs rowcol, because this variable is used when resizing +var lastDraggingRowcol = null; +var hoverLocation = null; +var draggingChangeLog = null; +canvas.addEventListener("mousedown", function(event) { + if (event.altKey) return; + if (event.button !== 0) return; + event.preventDefault(); + var location = getLocationFromEvent(event); + if (persistentState.showEditor && paintBrushTileCode != null) { + // editor tool + lastDraggingRowcol = getRowcol(level, location); + if (paintBrushTileCode === "select") selectionStart = location; + if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; + draggingChangeLog = []; + paintAtLocation(location, draggingChangeLog); + } else { + // playtime + var object = findObjectAtLocation(location); + if (object == null) return; + if (object.type !== SNAKE) return; + // active snake + activeSnakeId = object.id; + render(); + } +}); +canvas.addEventListener("dblclick", function(event) { + if (event.altKey) return; + if (event.button !== 0) return; + event.preventDefault(); + if (persistentState.showEditor && paintBrushTileCode === "select") { + // double click with select tool + var location = getLocationFromEvent(event); + var object = findObjectAtLocation(location); + if (object == null) return; + stopDragging(); + if (object.type === SNAKE) { + // edit snakes of this color + paintBrushTileCode = SNAKE; + paintBrushSnakeColorIndex = object.id % snakeColors.length; + } else if (object.type === BLOCK) { + // edit this particular block + paintBrushTileCode = BLOCK; + paintBrushBlockId = object.id; + } else if (object.type === FRUIT) { + // edit fruits, i guess + paintBrushTileCode = FRUIT; + } else throw unreachable(); + paintBrushTileCodeChanged(); + } +}); +document.addEventListener("mouseup", function(event) { + stopDragging(); +}); +function stopDragging() { + if (lastDraggingRowcol != null) { + // release the draggin' + lastDraggingRowcol = null; + paintBrushObject = null; + resizeDragAnchorRowcol = null; + pushUndo(uneditStuff, draggingChangeLog); + draggingChangeLog = null; + } +} +canvas.addEventListener("mousemove", function(event) { + if (!persistentState.showEditor) return; + var location = getLocationFromEvent(event); + var mouseRowcol = getRowcol(level, location); + if (lastDraggingRowcol != null) { + // Dragging Force - Through the Fruit and Flames + var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); + // we need to get rowcols for everything before we start dragging, because dragging might resize the world. + var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function(location) { + return getRowcol(level, location); + }); + path.forEach(function(rowcol) { + // convert to location at the last minute in case each of these steps is changing the coordinate system. + paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); + }); + lastDraggingRowcol = mouseRowcol; + hoverLocation = null; + } else { + // hovering + if (hoverLocation !== location) { + hoverLocation = location; + render(); + } + } +}); +canvas.addEventListener("mouseout", function() { + if (hoverLocation !== location) { + // turn off the hover when the mouse leaves + hoverLocation = null; + render(); + } +}); +function getLocationFromEvent(event) { + var r = Math.floor(eventToMouseY(event, canvas) / tileSize); + var c = Math.floor(eventToMouseX(event, canvas) / tileSize); + // since the canvas is centered, the bounding client rect can be half-pixel aligned, + // resulting in slightly out-of-bounds mouse events. + r = clamp(r, 0, level.height); + c = clamp(c, 0, level.width); + return getLocation(level, r, c); +} +function eventToMouseX(event, canvas) { return event.clientX - canvas.getBoundingClientRect().left; } +function eventToMouseY(event, canvas) { return event.clientY - canvas.getBoundingClientRect().top; } + +function selectAll() { + selectionStart = 0; + selectionEnd = level.map.length - 1; + setPaintBrushTileCode("select"); +} + +function setPaintBrushTileCode(tileCode) { + if (tileCode === "paste") { + // make sure we have something to paste + if (clipboardData == null) return; + } + if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { + // usually this means to fill in the selection + if (tileCode == null) { + // cancel selection + selectionStart = null; + selectionEnd = null; + return; + } + // fill in the selection + fillSelection(tileCode); + selectionStart = null; + selectionEnd = null; + return; + } + if (tileCode === SNAKE) { + if (paintBrushTileCode === SNAKE) { + // next snake color + paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; + } + } else if (tileCode === BLOCK) { + var blocks = getBlocks(); + if (paintBrushTileCode === BLOCK && blocks.length > 0) { + // cycle through block ids + blocks.sort(compareId); + if (paintBrushBlockId != null) { + (function() { + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].id === paintBrushBlockId) { + i += 1; + if (i < blocks.length) { + // next block id + paintBrushBlockId = blocks[i].id; + } else { + // new block id + paintBrushBlockId = null; + } + return; + } + } + throw unreachable() + })(); + } else { + // first one + paintBrushBlockId = blocks[0].id; + } + } else { + // new block id + paintBrushBlockId = null; + } + } else if (tileCode == null) { + // escape + if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { + // stop editing this block, but keep the block brush selected + tileCode = BLOCK; + paintBrushBlockId = null; + } + } + paintBrushTileCode = tileCode; + paintBrushTileCodeChanged(); +} +function paintBrushTileCodeChanged() { + paintButtonIdAndTileCodes.forEach(function(pair) { + var id = pair[0]; + var tileCode = pair[1]; + var backgroundStyle = ""; + var textColor = ""; + if (tileCode === paintBrushTileCode) { + if (tileCode === SNAKE) { + // show the color of the active snake in the color of the button + backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; + } else { + backgroundStyle = "linear-gradient(#4b91ff, #055ce4)"; + textColor = "white"; + } + } + document.getElementById(id).style.background = backgroundStyle; + document.getElementById(id).style.color = textColor; + }); + + var isSelectionMode = paintBrushTileCode === "select"; + ["cutButton", "copyButton"].forEach(function (id) { + document.getElementById(id).disabled = !isSelectionMode; + }); + document.getElementById("pasteButton").disabled = clipboardData == null; + + render(); +} + +function cutSelection() { + copySelection(); + fillSelection(SPACE); + render(); +} +function copySelection() { + var selectedLocations = getSelectedLocations(); + if (selectedLocations.length === 0) return; + var selectedObjects = []; + selectedLocations.forEach(function(location) { + var object = findObjectAtLocation(location); + if (object != null) addIfNotPresent(selectedObjects, object); + }); + setClipboardData({ + level: JSON.parse(JSON.stringify(level)), + selectedLocations: selectedLocations, + selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), + }); +} +function setClipboardData(data) { + // find the center + var minR = Infinity; + var maxR = -Infinity; + var minC = Infinity; + var maxC = -Infinity; + data.selectedLocations.forEach(function(location) { + var rowcol = getRowcol(data.level, location); + if (rowcol.r < minR) minR = rowcol.r; + if (rowcol.r > maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var offsetR = Math.floor((minR + maxR) / 2); + var offsetC = Math.floor((minC + maxC) / 2); + + clipboardData = data; + clipboardOffsetRowcol = {r:offsetR, c:offsetC}; + paintBrushTileCodeChanged(); +} +function fillSelection(tileCode) { + var changeLog = []; + var locations = getSelectedLocations(); + locations.forEach(function(location) { + if (level.map[location] !== tileCode) { + changeLog.push(["m", location, level.map[location], tileCode]); + level.map[location] = tileCode; + } + removeAnyObjectAtLocation(location, changeLog); + }); + pushUndo(uneditStuff, changeLog); +} +function getSelectedLocations() { + if (selectionStart == null || selectionEnd == null) return []; + var rowcol1 = getRowcol(level, selectionStart); + var rowcol2 = getRowcol(level, selectionEnd); + var r1 = rowcol1.r; + var c1 = rowcol1.c; + var r2 = rowcol2.r; + var c2 = rowcol2.c; + if (r2 < r1) { + var tmp = r1; + r1 = r2; + r2 = tmp; + } + if (c2 < c1) { + var tmp = c1; + c1 = c2; + c2 = tmp; + } + var objects = []; + var locations = []; + for (var r = r1; r <= r2; r++) { + for (var c = c1; c <= c2; c++) { + var location = getLocation(level, r, c); + locations.push(location); + var object = findObjectAtLocation(location); + if (object != null) addIfNotPresent(objects, object); + } + } + // select the rest of any partially-selected objects + objects.forEach(function(object) { + object.locations.forEach(function(location) { + addIfNotPresent(locations, location); + }); + }); + return locations; +} + +function setHeight(newHeight, changeLog) { + if (newHeight < level.height) { + // crop + for (var r = newHeight; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + removeAnyObjectAtLocation(location, changeLog); + // also delete non-space tiles + paintTileAtLocation(location, SPACE, changeLog); + } + } + level.map.splice(newHeight * level.width); + } else { + // expand + for (var r = level.height; r < newHeight; r++) { + for (var c = 0; c < level.width; c++) { + level.map.push(SPACE); + } + } + } + changeLog.push(["h", level.height, newHeight]); + level.height = newHeight; +} +function setWidth(newWidth, changeLog) { + if (newWidth < level.width) { + // crop + for (var r = level.height - 1; r >= 0; r--) { + for (var c = level.width - 1; c >= newWidth; c--) { + var location = getLocation(level, r, c); + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, SPACE, changeLog); + level.map.splice(location, 1); + } + } + } else { + // expand + for (var r = level.height - 1; r >= 0; r--) { + var insertionPoint = level.width * (r + 1); + for (var c = level.width; c < newWidth; c++) { + // boy is this inefficient. ... YOLO! + level.map.splice(insertionPoint, 0, SPACE); + } + } + } + + var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); + level.objects.forEach(function(object) { + object.locations = object.locations.map(transformLocation); + }); + + changeLog.push(["w", level.width, newWidth]); + level.width = newWidth; +} + +function newSnake(color, location) { + var snakes = findSnakesOfColor(color); + snakes.sort(compareId); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id !== i * snakeColors.length + color) break; + } + return { + type: SNAKE, + id: i * snakeColors.length + color, + dead: false, + locations: [location], + }; +} +function newBlock(location) { + var blocks = getBlocks(); + blocks.sort(compareId); + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].id !== i) break; + } + return { + type: BLOCK, + id: i, + dead: false, // unused + locations: [location], + }; +} +function newFruit(location) { + var fruits = getObjectsOfType(FRUIT); + fruits.sort(compareId); + for (var i = 0; i < fruits.length; i++) { + if (fruits[i].id !== i) break; + } + return { + type: FRUIT, + id: i, + dead: false, // unused + locations: [location], + }; +} +function paintAtLocation(location, changeLog) { + if (typeof paintBrushTileCode === "number") { + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, paintBrushTileCode, changeLog); + } else if (paintBrushTileCode === "resize") { + var toRowcol = getRowcol(level, location); + var dr = toRowcol.r - resizeDragAnchorRowcol.r; + var dc = toRowcol.c - resizeDragAnchorRowcol.c; + resizeDragAnchorRowcol = toRowcol; + if (dr !== 0) setHeight(level.height + dr, changeLog); + if (dc !== 0) setWidth(level.width + dc, changeLog); + } else if (paintBrushTileCode === "select") { + selectionEnd = location; + } else if (paintBrushTileCode === "paste") { + var hoverRowcol = getRowcol(level, location); + var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); + pastedData.selectedLocations.forEach(function(location) { + var tileCode = pastedData.level.map[location]; + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, tileCode, changeLog); + }); + pastedData.selectedObjects.forEach(function(object) { + // refresh the ids so there are no collisions. + if (object.type === SNAKE) { + object.id = newSnake(object.id % snakeColors.length).id; + } else if (object.type === BLOCK) { + object.id = newBlock().id; + } else if (object.type === FRUIT) { + object.id = newFruit().id; + } else throw unreachable(); + level.objects.push(object); + changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); + }); + } else if (paintBrushTileCode === SNAKE) { + var oldSnakeSerialization = serializeObjectState(paintBrushObject); + if (paintBrushObject != null) { + // keep dragging + if (paintBrushObject.locations[0] === location) return; // we just did that + // watch out for self-intersection + var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); + if (selfIntersectionIndex !== -1) { + // truncate from here back + paintBrushObject.locations.splice(selfIntersectionIndex); + } + } + + // make sure there's space behind us + paintTileAtLocation(location, SPACE, changeLog); + removeAnyObjectAtLocation(location, changeLog); + if (paintBrushObject == null) { + var thereWereNoSnakes = countSnakes() === 0; + paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); + level.objects.push(paintBrushObject); + if (thereWereNoSnakes) activateAnySnakePlease(); + } else { + // extend le snake + paintBrushObject.locations.unshift(location); + } + changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); + } else if (paintBrushTileCode === BLOCK) { + var objectHere = findObjectAtLocation(location); + if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { + // just start editing this block + paintBrushBlockId = objectHere.id; + } else { + // make a change + // make sure there's space behind us + paintTileAtLocation(location, SPACE, changeLog); + var thisBlock = null; + if (paintBrushBlockId != null) { + thisBlock = findBlockById(paintBrushBlockId); + } + var oldBlockSerialization = serializeObjectState(thisBlock); + if (thisBlock == null) { + // create new block + removeAnyObjectAtLocation(location, changeLog); + thisBlock = newBlock(location); + level.objects.push(thisBlock); + paintBrushBlockId = thisBlock.id; + } else { + var existingIndex = thisBlock.locations.indexOf(location); + if (existingIndex !== -1) { + // reclicking part of this object means to delete just part of it. + if (thisBlock.locations.length === 1) { + // goodbye + removeObject(thisBlock, changeLog); + paintBrushBlockId = null; + } else { + thisBlock.locations.splice(existingIndex, 1); + } + } else { + // add a tile to the block + removeAnyObjectAtLocation(location, changeLog); + thisBlock.locations.push(location); + } + } + changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); + delete blockSupportRenderCache[thisBlock.id]; + } + } else if (paintBrushTileCode === FRUIT) { + paintTileAtLocation(location, SPACE, changeLog); + removeAnyObjectAtLocation(location, changeLog); + var object = newFruit(location) + level.objects.push(object); + changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); + } else throw unreachable(); + render(); +} + +function paintTileAtLocation(location, tileCode, changeLog) { + if (level.map[location] === tileCode) return; + changeLog.push(["m", location, level.map[location], tileCode]); + level.map[location] = tileCode; +} + +function pushUndo(undoStuff, changeLog) { + // changeLog = [ + // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], + // // player input for snake 0, dr:-1, dc:0. has no effect on state. + // // "i" is always the first change in normal player movement. + // // if a changeLog does not start with "i", then it is an editor action. + // // animationQueue and freshlyRemovedAnimatedObjects + // // are used for animating re-move. + // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 + // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] + // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] + // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] + // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] + // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. + // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. + // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. + // 10, // the last change is always a declaration of the final width of the map. + // ]; + reduceChangeLog(changeLog); + if (changeLog.length === 0) return; + changeLog.push(level.width); + undoStuff.undoStack.push(changeLog); + undoStuff.redoStack = []; + paradoxes = []; + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; + + undoStuffChanged(undoStuff); +} +function reduceChangeLog(changeLog) { + for (var i = 0; i < changeLog.length - 1; i++) { + var change = changeLog[i]; + if (change[0] === "i") { + continue; // don't reduce player input + } else if (change[0] === "h") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "h") { + // combine + change[2] = otherChange[2]; + changeLog.splice(j, 1); + j--; + continue; + } else if (otherChange[0] === "w") { + continue; // no interaction between height and width + } else break; // no more reduction possible + } + if (change[1] === change[2]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === "w") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "w") { + // combine + change[2] = otherChange[2]; + changeLog.splice(j, 1); + j--; + continue; + } else if (otherChange[0] === "h") { + continue; // no interaction between height and width + } else break; // no more reduction possible + } + if (change[1] === change[2]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === "m") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "m" && otherChange[1] === change[1]) { + // combine + change[3] = otherChange[3]; + changeLog.splice(j, 1); + j--; + } else if (otherChange[0] === "w" || otherChange[0] === "h") { + break; // can't reduce accros resizes + } + } + if (change[2] === change[3]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === change[0] && otherChange[1] === change[1]) { + // combine + change[3] = otherChange[3]; + changeLog.splice(j, 1); + j--; + } else if (otherChange[0] === "w" || otherChange[0] === "h") { + break; // can't reduce accros resizes + } + } + if (deepEquals(change[2], change[3])) { + // no change + changeLog.splice(i, 1); + i--; + } + } else throw unreachable(); + } +} +function undo(undoStuff) { + if (undoStuff.undoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + undoOneFrame(undoStuff); + undoStuffChanged(undoStuff); +} +function reset(undoStuff) { + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + while (undoStuff.undoStack.length > 0) { + undoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); +} +function undoOneFrame(undoStuff) { + var doThis = undoStuff.undoStack.pop(); + var redoChangeLog = []; + undoChanges(doThis, redoChangeLog); + if (redoChangeLog.length > 0) { + redoChangeLog.push(level.width); + undoStuff.redoStack.push(redoChangeLog); + } + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; +} +function redo(undoStuff) { + if (undoStuff.redoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + redoOneFrame(undoStuff); + undoStuffChanged(undoStuff); +} +function redoAll(undoStuff) { + cs = true; + if (undoStuff.redoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + + while (undoStuff.redoStack.length > 0) { + redoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); + + if(checkResult) { + cr = true; + render(); + } + else { + render(); + } +} +function copyToClipboard(text) { + var dummy = document.createElement("textarea"); + // to avoid breaking orgain page when copying more words + // cant copy when adding below this code + // dummy.style.display = 'none' + document.body.appendChild(dummy); + //Be careful if you use texarea. setAttribute('value', value), which works with "input" does not work with "textarea". – Eduard + dummy.value = text; + dummy.select(); + document.execCommand("copy"); + document.body.removeChild(dummy); +} +function unreset(undoStuff) { + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + while (undoStuff.redoStack.length > 0) { + redoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); + + // don't animate the last frame + animationQueue = []; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = []; +} +function redoOneFrame(undoStuff) { + var doThis = undoStuff.redoStack.pop(); + var undoChangeLog = []; + undoChanges(doThis, undoChangeLog); + if (undoChangeLog.length > 0) { + undoChangeLog.push(level.width); + undoStuff.undoStack.push(undoChangeLog); + } + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; +} +function undoChanges(changes, changeLog) { + var widthContext = changes.pop(); + var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); + for (var i = changes.length - 1; i >= 0; i--) { + var paradoxDescription = undoChange(changes[i]); + if (paradoxDescription != null) paradoxes.push(paradoxDescription); + } + + var lastChange = changes[changes.length - 1]; + if (lastChange[0] === "i") { + // replay animation + animationQueue = lastChange[4]; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = lastChange[5]; + animationStart = new Date().getTime(); + } + + function undoChange(change) { + // note: everything here is going backwards: to -> from + if (change[0] === "i") { + // no state change, but preserve the intention. + changeLog.push(change); + return null; + } else if (change[0] === "h") { + // change height + var fromHeight = change[1]; + var toHeight = change[2]; + if (level.height !== toHeight) return "Impossible"; + setHeight(fromHeight, changeLog); + } else if (change[0] === "w") { + // change width + var fromWidth = change[1]; + var toWidth = change[2]; + if (level.width !== toWidth) return "Impossible"; + setWidth(fromWidth, changeLog); + } else if (change[0] === "m") { + // change map tile + var location = transformLocation(change[1]); + var fromTileCode = change[2]; + var toTileCode = change[3]; + if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; + if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; + paintTileAtLocation(location, fromTileCode, changeLog); + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { + // change object + var type = change[0]; + var id = change[1]; + var fromDead = change[2][0]; + var toDead = change[3][0]; + var fromLocations = change[2][1].map(transformLocation); + var toLocations = change[3][1].map(transformLocation); + if (fromLocations.filter(function(location) { return location >= level.map.length; }).length > 0) { + return "Can't move " + describe(type, id) + " out of bounds"; + } + var object = findObjectOfTypeAndId(type, id); + if (toLocations.length !== 0) { + // should exist at this location + if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; + if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; + if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; + // doit + if (fromLocations.length !== 0) { + var oldState = serializeObjectState(object); + object.locations = fromLocations; + object.dead = fromDead; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + } else { + removeObject(object, changeLog); + } + } else { + // shouldn't exist + if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; + // doit + object = { + type: type, + id: id, + dead: fromDead, + locations: fromLocations, + }; + level.objects.push(object); + changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); + } + } else throw unreachable(); + } +} +function describe(arg1, arg2) { + // describe(0) -> "Space" + // describe(SNAKE, 0) -> "Snake 0 (Red)" + // describe(object) -> "Snake 0 (Red)" + // describe(BLOCK, 1) -> "Block 1" + // describe(FRUIT) -> "Fruit" + if (typeof arg1 === "number") { + switch (arg1) { + case SPACE: return "Space"; + case WALL: return "a Wall"; + case SPIKE: return "Spikes"; + case EXIT: return "an Exit"; + case PORTAL: return "a Portal"; + case PLATFORM: return "a Platform"; + case WOODPLATFORM: return "a Wooden Platform"; + case ONEWAYWALLU: return "a One Way Wall (facing U)"; + case ONEWAYWALLD: return "a One Way Wall (facing D)"; + case ONEWAYWALLL: return "a One Way Wall (facing L)"; + case ONEWAYWALLR: return "a One Way Wall (facing R)"; + case CLOSEDLIFT: return "a Closed Lift"; + case OPENLIFT: return "an Open Lift"; + case CLOUD: return "a Cloud"; + case BUBBLE: return "a Bubble"; + case LAVA: return "Lava"; + case WATER: return "Water"; + default: throw unreachable(); + } + } + if (arg1 === SNAKE) { + var color = (function() { + switch (snakeColors[arg2 % snakeColors.length]) { + case "#fd0c0b": return " (Red)"; + case "#18d11f": return " (Green)"; + case "#004cff": return " (Blue)"; + case "#fdc122": return " (Yellow)"; + default: throw unreachable(); + } + })(); + return "Snake " + arg2 + color; + } + if (arg1 === BLOCK) { + return "Block " + arg2; + } + if (arg1 === FRUIT) { + return "Fruit"; + } + if (typeof arg1 === "object") return describe(arg1.type, arg1.id); + throw unreachable(); +} + +function undoStuffChanged(undoStuff) { + var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; + document.getElementById(undoStuff.spanId).textContent = movesText; + document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; + document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; + + // render paradox display + var uniqueParadoxes = []; + var paradoxCounts = []; + paradoxes.forEach(function(paradoxDescription) { + var index = uniqueParadoxes.indexOf(paradoxDescription); + if (index !== -1) { + paradoxCounts[index] += 1; + } else { + uniqueParadoxes.push(paradoxDescription); + paradoxCounts.push(1); + } + }); + + updateDirtyState(); + + if (unmoveStuff.redoStack.length === 0) { + document.getElementById("removeButton").classList.remove("click-me"); + } +} + +var CLEAN_NO_TIMELINES = 0; +var CLEAN_WITH_REDO = 1; +var REPLAY_DIRTY = 2; +var EDITOR_DIRTY = 3; +var dirtyState = CLEAN_NO_TIMELINES; +var editorHasBeenTouched = false; +function updateDirtyState() { + if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { + dirtyState = EDITOR_DIRTY; + } else if (unmoveStuff.undoStack.length > 0) { + dirtyState = REPLAY_DIRTY; + } else if (unmoveStuff.redoStack.length > 0) { + dirtyState = CLEAN_WITH_REDO; + } else { + dirtyState = CLEAN_NO_TIMELINES; + } + + var saveLevelButton = document.getElementById("saveLevelButton"); + // the save button clears your timelines + saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; + if (dirtyState >= EDITOR_DIRTY) { + // you should save + saveLevelButton.classList.add("click-me"); + } else { + saveLevelButton.classList.remove("click-me"); + } + +} +function haveCheatcodesBeenUsed() { + return !unmoveStuff.undoStack.every(function(changeLog) { + // normal movement always starts with "i". + return changeLog[0][0] === "i"; + }); +} + +var persistentState = { + showEditor: false, +}; +function savePersistentState() { + localStorage.snakefall = JSON.stringify(persistentState); +} +function loadPersistentState() { + try { + persistentState = JSON.parse(localStorage.snakefall); + } catch (e) { + } + persistentState.showEditor = !!persistentState.showEditor; + showEditorChanged(); +} +var isGravityEnabled = true; +function isGravity() { + return isGravityEnabled || !persistentState.showEditor; +} +var isCollisionEnabled = true; +function isCollision() { + return isCollisionEnabled || !persistentState.showEditor; +} +function isAnyCheatcodeEnabled() { + return persistentState.showEditor && ( + !isGravityEnabled || !isCollisionEnabled + ); +} +var themeName = "Spring"; //Gooby +var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle, experimentalColors; +var curlyOutline = false; + +var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; +var bg2 = "rgba(254, 198, 145 * rgba(255, 192, 133"; +var bg3 = "rgba(145, 254, 198 * rgba(117, 255, 192"; +var bg4 = "rgba(7, 7, 83 * rgba(0, 0, 70"; + +var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; +var snakeColors2 = ["#f00", "#0f0", "#00f", "#ff0"]; +var snakeColors3 = ["#BA145C", "#E91624", "#F75802", "#FEFE28"]; + +var fruitColors1 = ["#ff0066","#ff36a6","#ff6b1f","#ff9900","#ff2600"]; +var fruitColors2 = ["black","black","black","black","black"]; + +var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spike, support, box, bolt +var spikeColors2 = ["gray", "black", "white", "black"]; +var spikeColors3 = ["#333", "#333", "#333", "#777"]; + +var blockColors1 = [ + ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"], + ["#853641","#963c84","#753d88","#5d3a96","#3a3990"] +]; +var blockColors2 = [ + ["#999"], + ["#999"] +]; +var blockColors3 = [ + ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"], + ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] +]; +var blockColors4 = [ + ["#150612", "#a52e8b", "#990077", "#d917af", "#4d003c"], + ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] +]; + +var fontSize = tileSize*5; +var textStyle1 = ["" + fontSize + "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose +var textStyle2 = ["" + fontSize + "px Impact", "#5702c6", "#ff0098"]; +var textStyle3 = ["" + fontSize + "px Impact", "#BA145C", "#F75802"]; +var textStyle4 = ["" + fontSize + "px Impact", "#ff0", "#f00"]; + +var experimentalColors1 = ["white", "#ffccff"]; +var experimentalColors2 = ["white", "#FEFE28"]; + +var themeCounter = 0; + +var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor, textStyle, experimentalColors + //["sky",], + ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], + ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], + ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], + ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], + ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], + ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] +]; + + +function showEditorChanged() { + document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; + ["editorDiv", "editorPane"].forEach(function(id) { + document.getElementById(id).style.display = persistentState.showEditor ? "none" : "none"; + }); + + render(); +} + +function move(dr, dc) { + if (!isAlive()) return; + animationQueue = []; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = []; + animationStart = new Date().getTime(); + var activeSnake = findActiveSnake(); + var headRowcol = getRowcol(level, activeSnake.locations[0]); + var newRowcol = {r:headRowcol.r + dr, c:headRowcol.c + dc}; + if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; + var newLocation = getLocation(level, newRowcol.r, newRowcol.c); + var changeLog = []; + + // The changeLog for a player movement starts with the input + // when playing normally. + if (!isAnyCheatcodeEnabled()) { + changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); + } + + var ate = false; + var pushedObjects = []; + + //track ClosedLifts that had objects on them + var occupiedClosedLift = getOccupiedClosedLiftLocations(); + + if (isCollision()) { + var newTile = level.map[newLocation]; + if (newTile === BUBBLE || newTile === CLOUD) + paintTileAtLocation(newLocation, SPACE, changeLog); + else if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile + var otherObject = findObjectAtLocation(newLocation); + if (otherObject != null) { + if (otherObject === activeSnake) return; // can't push yourself + if (otherObject.type === FRUIT) { + // eat + removeObject(otherObject, changeLog); + ate = true; + } else if (isTileCodeAir(activeSnake, null, newTile, dr, dc)) { + otherObject = findObjectAtLocation(newLocation); + if (otherObject != null) { + if (otherObject === activeSnake) return; // can't push yourself + // push objects + if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; + } + } else return; // can't go through that tile + } + } + + // slither forward + var activeSnakeOldState = serializeObjectState(activeSnake); + var size1 = activeSnake.locations.length === 1; + var slitherAnimations = [ + 70, + [ + // size-1 snakes really do more of a move than a slither + size1 ? MOVE_SNAKE : SLITHER_HEAD, + activeSnake.id, + dr, + dc, + ] + ]; + activeSnake.locations.unshift(newLocation); + if (!ate) { + for(var i = 1; i 0) { + var anySnakesDied = false; + dyingObjects.forEach(function(object) { + if (object.type === SNAKE) { + // look what you've done + var oldState = serializeObjectState(object); + object.dead = true; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + anySnakesDied = true; + } else if (object.type === BLOCK) { + // a box fell off the world + removeAnimatedObject(object, changeLog); + removeFromArray(fallingObjects, object); + exitAnimationQueue.push([ + 200, + [ + DIE_BLOCK, + object.id, + 0, 0 + ], + ]); + didAnything = true; + } else throw unreachable(); + }); + if (anySnakesDied) break; + } + if (fallingObjects.length > 0) { + moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); + didAnything = true; + } + + occupiedClosedLift = openLift(occupiedClosedLift, changeLog); + + if (!didAnything) break; + Array.prototype.push.apply(animationQueue, exitAnimationQueue); + if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); + } + + pushUndo(unmoveStuff, changeLog); + render(); +} + +function combineOldAndNewLiftOccupations(oldOccupiedClosedLift) +{ + var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); + var newlyOccupiedClosedLift = getSetSubtract(newOccupiedClosedLift, oldOccupiedClosedLift); + return oldOccupiedClosedLift.concat(newlyOccupiedClosedLift); +} + +function openLift(oldOccupiedClosedLift, changeLog) +{ + var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); + var nowUnoccupiedClosedLift = getSetSubtract(oldOccupiedClosedLift, newOccupiedClosedLift); + for (var i = 0; i < nowUnoccupiedClosedLift.length; i++) { + paintTileAtLocation(nowUnoccupiedClosedLift[i], OPENLIFT, changeLog); + } + return newOccupiedClosedLift; +} + +function getSetSubtract(array1, array2) { + if (array1.length === 0) return []; + return array1.filter(function(x) { return array2.indexOf(x) == -1; }); +} + +function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects) { + // pusher can be null (for gravity) + pushedObjects.push(pushedObject); + // find forward locations + var forwardLocations = []; + for (var i = 0; i < pushedObjects.length; i++) { + pushedObject = pushedObjects[i]; + for (var j = 0; j < pushedObject.locations.length; j++) { + var rowcol = getRowcol(level, pushedObject.locations[j]); + var forwardRowcol = {r:rowcol.r + dr, c:rowcol.c + dc}; + if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { + if (dyingObjects == null) { + // can't push things out of bounds + return false; + } else { + // this thing is going to fall out of bounds + addIfNotPresent(dyingObjects, pushedObject); + addIfNotPresent(pushedObjects, pushedObject); + continue; + } + } + var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); + if (dr === 1 && level.map[forwardLocation] === PLATFORM) { + // this platform holds us, unless we're going through it + var neighborLocations; + if (pushedObject.type === SNAKE) { + neighborLocations = []; + if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); + if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); + } else if (pushedObject.type === BLOCK) { + neighborLocations = pushedObject.locations; + } else throw asdf; + if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface + // we slip right past it + } + var yetAnotherObject = findObjectAtLocation(forwardLocation); + if (yetAnotherObject != null) { + if (yetAnotherObject.type === FRUIT) { + // not pushable + return false; + } + if (yetAnotherObject === pusher) { + // indirect pushing ourselves. + // special check for when we're indirectly pushing the tip of our own tail. + if (forwardLocation === pusher.locations[pusher.locations.length -1]) { + // for some reason this is ok. ------------ THIS IS THE TAIL GLITCH + continue; + } + return false; + } + addIfNotPresent(pushedObjects, yetAnotherObject); + if(level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work + } else + addIfNotPresent(forwardLocations, forwardLocation); + } + } + // check forward locations + for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform, saw no effect but left new code + var forwardLocation = forwardLocations[i]; + // many of these locations can be inside objects, + // but that means the tile must be air, + // and we already know pushing that object. + var tileCode = level.map[forwardLocation]; + var object = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); + if (!isTileCodeAir(pusher, object, tileCode, dr, dc)) { + if (dyingObjects != null) { + if (tileCode === SPIKE) { + // uh... which object was this again? + if (object.type === SNAKE) { + // ouch! + addIfNotPresent(dyingObjects, object); + continue; + } + + } + else if (tileCode === LAVA) { + if (object.type === SNAKE || object.type === BLOCK) { + addIfNotPresent(dyingObjects, object); + continue; + } + } + else if (tileCode === WATER) { + if (object.type === BLOCK) { + addIfNotPresent(dyingObjects, object); + continue; + } + } + } + // can't push into something solid + return false; + } + } + // the push is go + return true; +} + +function activateAnySnakePlease() { + var snakes = getSnakes(); + if (snakes.length === 0) return; // nope.avi + activeSnakeId = snakes[0].id; +} + +function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations, changeLog, animations) { + objects.forEach(function(object) { + var oldState = serializeObjectState(object); + var oldPortals = getSetIntersection(portalLocations, object.locations); + for (var i = 0; i < object.locations.length; i++) { + object.locations[i] = offsetLocation(object.locations[i], dr, dc); + if (level.map[object.locations[i]] == BUBBLE || level.map[object.locations[i]] == CLOUD) + paintTileAtLocation(object.locations[i], SPACE, changeLog); + } + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + animations.push([ + "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK + object.id, + dr, + dc, + ]); + + var newPortals = getSetIntersection(portalLocations, object.locations); + var activatingPortals = newPortals.filter(function(portalLocation) { + return oldPortals.indexOf(portalLocation) === -1; + }); + if (activatingPortals.length === 1) { + // exactly one new portal we're touching. activate it + portalActivationLocations.push(activatingPortals[0]); + } + }); +} + +function activatePortal(portalLocations, portalLocation, animations, changeLog) { + var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; + var portalRowcol = getRowcol(level, portalLocation); + var otherPortalRowcol = getRowcol(level, otherPortalLocation); + var delta = {r:otherPortalRowcol.r - portalRowcol.r, c:otherPortalRowcol.c - portalRowcol.c}; + + var object = findObjectAtLocation(portalLocation); + var newLocations = []; + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r + delta.r; + var c = rowcol.c + delta.c; + if (!isInBounds(level, r, c)) return false; // out of bounds + newLocations.push(getLocation(level, r, c)); + } + + for (var i = 0; i < newLocations.length; i++) { + var location = newLocations[i]; + if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile + var otherObject = findObjectAtLocation(location); + if (otherObject != null && otherObject !== object) return; // blocked by object + } + + // zappo presto! + var oldState = serializeObjectState(object); + object.locations = newLocations; + for (var i = 0; i < newLocations.length; i++) { + var location = newLocations[i]; + if (level.map[location] == BUBBLE || level.map[location] == CLOUD) //changed this despite bubble working perfectly without it + paintTileAtLocation(location, SPACE, changeLog); + } + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); +} + +function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { + switch (tileCode) + { + case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; + case WOODPLATFORM: case BUBBLE: return pusher != null; + case PLATFORM: return dr != 1; + case ONEWAYWALLU: return dr != 1; + case ONEWAYWALLD: return dr != -1; + case ONEWAYWALLL: return dc != 1; + case ONEWAYWALLR: return dc != -1; + default: return false; + } +} + +function addIfNotPresent(array, element) { + if (array.indexOf(element) !== -1) return; + array.push(element); +} +function removeAnyObjectAtLocation(location, changeLog) { + var object = findObjectAtLocation(location); + if (object != null) removeObject(object, changeLog); +} +function removeAnimatedObject(object, changeLog) { + removeObject(object, changeLog); + freshlyRemovedAnimatedObjects.push(object); +} +function removeObject(object, changeLog) { + removeFromArray(level.objects, object); + changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0,[]]]); + if (object.type === SNAKE && object.id === activeSnakeId) { + activateAnySnakePlease(); + } + if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { + // no longer editing an object that doesn't exit + paintBrushBlockId = null; + } + if (object.type === BLOCK) { + delete blockSupportRenderCache[object.id]; + } +} +function removeFromArray(array, element) { + var index = array.indexOf(element); + if (index === -1) throw unreachable(); + array.splice(index, 1); +} +function findActiveSnake() { + var snakes = getSnakes(); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) return snakes[i]; + } + throw unreachable(); +} +function findBlockById(id) { + return findObjectOfTypeAndId(BLOCK, id); +} +function findSnakesOfColor(color) { + return level.objects.filter(function(object) { + if (object.type !== SNAKE) return false; + return object.id % snakeColors.length === color; + }); +} +function findObjectOfTypeAndId(type, id) { + for (var i = 0; i < level.objects.length; i++) { + var object = level.objects[i]; + if (object.type === type && object.id === id) return object; + } + return null; +} +function findObjectAtLocation(location) { + for (var i = 0; i < level.objects.length; i++) { + var object = level.objects[i]; + if (object.locations.indexOf(location) !== -1) + return object; + } + return null; +} +function isUneatenFruit() { + return getObjectsOfType(FRUIT).length > 0; +} +function getActivePortalLocations() { + var portalLocations = getPortalLocations(); + if (portalLocations.length !== 2) return []; // nice try + return portalLocations; +} +function getPortalLocations() { + var result = []; + for (var i = 0; i < level.map.length; i++) { + if (level.map[i] === PORTAL) result.push(i); + } + return result; +} +function countSnakes() { + return getSnakes().length; +} +function getSnakes() { + return getObjectsOfType(SNAKE); +} +function getBlocks() { + return getObjectsOfType(BLOCK); +} +function getOccupiedClosedLiftLocations() +{ + var result = []; + for (var i = 0; i < level.map.length; i++) { + if (level.map[i] === CLOSEDLIFT) { + if (findObjectAtLocation(i)) + result.push(i); + } + } + return result; +} +function getObjectsOfType(type) { + return level.objects.filter(function(object) { + return object.type == type; + }); +} +function isDead() { + if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; + return getSnakes().filter(function(snake) { + return !!snake.dead; + }).length > 0; +} +function isAlive() { + return countSnakes() > 0 && !isDead(); +} + +var activeSnakeId = null; + +var SLITHER_HEAD = "sh"; +var SLITHER_TAIL = "st"; +var MOVE_SNAKE = "ms"; +var MOVE_BLOCK = "mb"; +var TELEPORT_SNAKE = "ts"; +var TELEPORT_BLOCK = "tb"; +var EXIT_SNAKE = "es"; +var DIE_SNAKE = "ds"; +var DIE_BLOCK = "db"; +var INFINITE_LOOP = "il"; +var animationQueue = [ + // // sequence of disjoint animation groups. + // // each group completes before the next begins. + // [ + // 70, // duration of this animation group + // // multiple things to animate simultaneously + // [ + // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, + // objectId, + // dr, + // dc, + // ], + // [ + // INFINITE_LOOP, + // loopSizeNotIncludingThis, + // ], + // ], +]; +var animationQueueCursor = 0; +var animationStart = null; // new Date().getTime() +var animationProgress; // 0.0 <= x < 1.0 +var freshlyRemovedAnimatedObjects = []; + +// render the support beams for blocks into a temporary buffer, and remember it. +// this is due to stencil buffers causing slowdown on some platforms. see #25. +var blockSupportRenderCache = { + // id: canvas, + // "0": document.createElement("canvas"), +}; + +function render() { + if (level == null) return; + if (animationQueueCursor < animationQueue.length) { + var animationDuration = animationQueue[animationQueueCursor][0]; + animationProgress = (new Date().getTime() - animationStart) / animationDuration; + if (animationProgress >= 1.0) { + // animation group complete + animationProgress -= 1.0; + animationQueueCursor++; + if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { + var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; + animationQueueCursor -= infiniteLoopSize; + } + animationStart = new Date().getTime(); + } + } + if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; + canvas.width = tileSize * level.width; + canvas.height = tileSize * level.height; + var context = canvas.getContext("2d"); //Gooby + + themeName = themes[themeCounter][0]; + if(themeName!="sky"){ + background = themes[themeCounter][1]; + material = themes[themeCounter][2]; + surface = themes[themeCounter][3]; + curlyOutline = themes[themeCounter][4]; + snakeColors = themes[themeCounter][5]; + blockColors = themes[themeCounter][6]; + spikeColors = themes[themeCounter][7]; + fruitColors = themes[themeCounter][8]; + textStyle = themes[themeCounter][10]; + experimentalColors = themes[themeCounter][11]; + + if(background.substr(0,1) == "#") { + context.fillStyle = background; + context.fillRect(0, 0, canvas.width, canvas.height); + } + else{ + for(var i = 0; i maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var image = blockSupportRenderCache[object.id]; + if (image == null) { + // render the support beams to a buffer + blockSupportRenderCache[object.id] = image = document.createElement("canvas"); + image.width = (maxC - minC + 1) * tileSize; + image.height = (maxR - minR + 1) * tileSize; + var bufferContext = image.getContext("2d"); + // Make a stencil that excludes the insides of blocks. + // Then when we render the support beams, we won't see the supports inside the block itself. + bufferContext.beginPath(); + // Draw a path around the whole screen in the opposite direction as the rectangle paths below. + // This means that the below rectangles will be removing area from the greater rectangle. + bufferContext.rect(image.width, 0, -image.width, image.height); + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r - minR; + var c = rowcol.c - minC; + bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); + } + bufferContext.clip(); + for (var i = 0; i < object.locations.length - 1; i++) { + var rowcol1 = getRowcol(level, object.locations[i]); + rowcol1.r -= minR; + rowcol1.c -= minC; + var rowcol2 = getRowcol(level, object.locations[i + 1]); + rowcol2.r -= minR; + rowcol2.c -= minC; + var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; + drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); + drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); + } + } + var r = minR + animationDisplacementRowcol.r; + var c = minC + animationDisplacementRowcol.c; + context.drawImage(image, c * tileSize, r * tileSize); + }); + + if(!cs) { + // terrain + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + var tileCode = level.map[location]; + drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids + } + } + } + + for(var i = 0; i6) { color= color.substring(1,color.length)} + var rgb = parseInt(color, 16); + var r = Math.abs(((rgb >> 16) & 0xFF)+v); if (r>255) r=r-(r-255); + var g = Math.abs(((rgb >> 8) & 0xFF)+v); if (g>255) g=g-(g-255); + var b = Math.abs((rgb & 0xFF)+v); if (b>255) b=b-(b-255); + r = Number(r < 0 || isNaN(r)) ? 0 : ((r > 255) ? 255 : r).toString(16); + if (r.length == 1) r = '0' + r; + g = Number(g < 0 || isNaN(g)) ? 0 : ((g > 255) ? 255 : g).toString(16); + if (g.length == 1) g = '0' + g; + b = Number(b < 0 || isNaN(b)) ? 0 : ((b > 255) ? 255 : b).toString(16); + if (b.length == 1) b = '0' + b; + return "#" + r + g + b; +} + + function drawObject(object) { + switch (object.type) { + case SNAKE: + var falling = false; + var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); + if (animationDisplacementRowcol.r != 0) falling = true; + var lastRowcol = null + var nextRowcol = null + var color = snakeColors[object.id % snakeColors.length]; + var colorIndex = object.id % snakeColors.length; + var altColor = getTintedColor(color, 50); + if(themeName==="Classic") altColor = color; + var headRowcol; + var orientation = 10; + for (var i = 0; i < object.locations.length; i++) { + var animation; + var rowcol; + if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward + rowcol = getRowcol(level, object.locations[i]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else if (i === object.locations.length) { + // animated tail? + if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { + // animate tail slithering to catch up + rowcol = getRowcol(level, object.locations[i-1]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else { + // no animated tail needed + break; + } + } else rowcol = getRowcol(level, object.locations[i]); + + lastRowcol = getRowcol(level, object.locations[i-1]); //closer to head + nextRowcol = getRowcol(level, object.locations[i+1]); //closer to tail + var rc = rowcol; + var lrc = lastRowcol; + var nrc = nextRowcol; + + if (object.dead) { //if snake dies after moving left or right, head is positioned down + rowcol.r += .5; + lastRowcol.r += .5; + nextRowcol.r += .5; + falling = true; + } + rowcol.r += animationDisplacementRowcol.r; + rowcol.c += animationDisplacementRowcol.c; + lastRowcol.r += animationDisplacementRowcol.r; + lastRowcol.c += animationDisplacementRowcol.c; + nextRowcol.r += animationDisplacementRowcol.r; + nextRowcol.c += animationDisplacementRowcol.c; + + var cx = rowcol.c * tileSize; + var cy = rowcol.r * tileSize; + + if (i === 0) { + context.fillStyle = color; + headRowcol = rowcol; + + //determines orientation of face + if(!falling) nextRowcol = getRowcol(level, object.locations[1]); + if (nextRowcol.r < rowcol.r) { //last move down + roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false); //draw head + if(colorIndex === 0) orientation = 2; + else if(colorIndex === 1) orientation = 6; + else if(colorIndex === 2) orientation = 3; + else if(colorIndex === 3) orientation = 5; + } + else if (nextRowcol.r > rowcol.r) { //last move up + roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false); //draw head + if(colorIndex === 0) orientation = 0; + else if(colorIndex === 1) orientation = 4; + else if(colorIndex === 2) orientation = 1; + else if(colorIndex === 3) orientation = 7; + } + else if (nextRowcol.c < rowcol.c) { //last move right + roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false); //draw head + if(colorIndex === 0) orientation = 1; + else if(colorIndex === 1) orientation = 5; + else if(colorIndex === 2) orientation = 2; + else if(colorIndex === 3) orientation = 4; + } + else if (nextRowcol.c > rowcol.c) { //last move left + roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false); //draw head + if(colorIndex === 0) orientation = 3; + else if(colorIndex === 1) orientation = 7; + else if(colorIndex === 2) orientation = 0; + else if(colorIndex === 3) orientation = 6; + } + else { + roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); //draw head + orientation = 10; + } + } else { + if(i % 2 == 0) context.fillStyle = color; + else context.fillStyle = altColor; + + if (i === object.locations.length-1) { + if(lastRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false);} + else if(lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false);} + else if(lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false);} + else if(lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false);} + } + else if (i != object.locations.length-1 && i != object.locations.length) { + if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} + else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} + else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} + else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} + + else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} + else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} + else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} + else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} + + else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, 0, true, false);} + } + else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); + } + } + drawFace(object.id, headRowcol.c, headRowcol.r, orientation); + break; + case BLOCK: + drawBlock(object); + break; + case FRUIT: + rowcol = getRowcol(level, object.locations[0]); + var c = rowcol.c; + var r = rowcol.r; + var startC = c*tileSize+tileSize/2; + var startR = r*tileSize+tileSize*.2; + var resize = tileSize * 1.7; + context.fillStyle = fruitColors[object.id % fruitColors.length]; + if(themeName != "Classic"){ + if(surface == "rainbow") { + context.fillStyle = "black"; + context.lineWidth = tileSize/8; + context.strokeStyle = "white"; + resize = tileSize * 1.4; + } + //context.fillStyle = "#ff6b45"; + context.beginPath(); + context.moveTo(startC, startR); + context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC-resize*.25, startR-resize*.1, startC-resize*.3, startR+resize*.05); + context.bezierCurveTo(startC-resize*.35, startR+resize*.15, startC-resize*.3, startR+resize*.6, startC, startR+resize*.5); + context.bezierCurveTo(startC+resize*.3, startR+resize*.6, startC+resize*.35, startR+resize*.15, startC+resize*.3, startR+resize*.05); + context.bezierCurveTo(startC+resize*.25, startR-resize*.05, startC+resize*.1, startR-resize*.1, startC, startR); + context.closePath(); + context.fill(); + if(surface == "rainbow") context.stroke(); + + context.beginPath(); + context.moveTo(startC,startR); + context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); + context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); + context.fillStyle = themes[themeCounter][9]; + context.fill(); + } + else drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); + break; + default: throw unreachable(); + } + } + +function drawPlatform(r, c, adjacentTiles) { + newPlatform(r, c, isPlatform); + + function isPlatform(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === PLATFORM; + } + + /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*1, r*tileSize); + context.lineTo(c*tileSize, r*tileSize); + context.closePath(); + context.rect(c*tileSize, r*tileSize+tileSize*.2857, tileSize, tileSize*.1429);*/ + + /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.25, r*tileSize+tileSize*.2, c*tileSize+tileSize*.25, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.75, r*tileSize+tileSize*.2, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.lineTo((c+1)*tileSize, r*tileSize); + context.lineTo(c*tileSize, r*tileSize);*/ + + /*context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.arc((c + 3/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.arc((c + 1/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.lineTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize+tileSize, r*tileSize);*/ + + //context.closePath(); + //context.fillStyle = "#000066"; + //ontext.fill(); + //context.stroke(); +} + +function newPlatform(r, c, isOccupied){ + + var x1 = .05; + var x2 = .05; + if(isOccupied(-1,0)) x1 = 0; + if(isOccupied(1,0)) x2 = 0; + + var platformColors = ["#ffcccc", "#ffe0cc", "#ffffcc", "#e6ffe6", "#e6e6ff"]; + for(var i = 0; i<5; i++){ + var j = i-1; + if(j<0) j = 0; + context.beginPath(); + context.moveTo(c*tileSize+tileSize*(i*x1), r*tileSize+tileSize*(.05 + (.1 * i) - (j * .02))); + context.strokeStyle = platformColors[i]; + context.lineWidth = tileSize*(.1-(i*.02)); + context.lineTo(c*tileSize+tileSize*(1-(i*x2)), r*tileSize+tileSize*(.05 + (.1 * i) - (j * .02))); + context.stroke(); + } +} + + function drawOneWayWall(fillStyle, r, c, dr, dc) { + context.lineWidth = 2; + context.strokeStyle = "#333"; + context.beginPath(); + + if (dr == -1) { + context.moveTo(c * tileSize, r * tileSize + tileSize/2); + context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); + context.stroke(); + context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); + context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); + } + else if (dr == 1) { + context.moveTo(c * tileSize, r * tileSize + tileSize/2); + context.lineTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); + context.stroke(); + context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); + context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); + } + else if (dc == -1) { + context.moveTo(c * tileSize + tileSize/2, r * tileSize); + context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); + context.stroke(); + context.moveTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); + context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); + } + else if (dc == 1) { + context.moveTo(c * tileSize + tileSize/2, r * tileSize); + context.lineTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); + context.stroke(); + context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); + context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); + } + + context.stroke(); + context.lineWidth = 0; + + context.fillStyle = fillStyle; + if (dr == -1) roundRect(context, c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15, 2, true, false); + else if (dr == 1) roundRect(context, c * tileSize - tileSize/15, (r + 1) * tileSize - tileSize/15 - tileSize/4, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15, 2, true, false); + else if (dc == -1) roundRect(context, c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15, 2, true, false); + else if (dc == 1) roundRect(context, (c + 1) * tileSize - tileSize/15 - tileSize/4, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15, 2, true, false); + } + + function drawBubble(r, c) { + bubbleX = c*tileSize; + var grd = context.createRadialGradient(bubbleX, r*tileSize, 0, bubbleX, r*tileSize, tileSize); + grd.addColorStop(0, "rgba(255,255,255,.9)"); + grd.addColorStop(1, "rgba(255,255,255,.2)"); + context.fillStyle = grd; + context.lineWidth = .5; + context.strokeStyle = "rgba(200,200,200,.2)"; + + context.beginPath(); + context.arc(c*tileSize+tileSize*.5, r*tileSize+tileSize*.5, tileSize/2, 0, 2*Math.PI); + context.fill(); + context.stroke(); + } + +function drawLiquid(r, c, type, adjacentTiles) { + newLiquid(r, c, type, isSameLiquid); + + function isSameLiquid(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === type; + } +} + +function newLiquid(r, c, type, isOccupied){ + context.save(); + var tubColor; + if(type == LAVA) { + context.fillStyle = "#ffbf00"; + context.strokeStyle = "red"; + tubColor = "black"; + } + else { + context.fillStyle = "#1a8cff"; + context.strokeStyle = "#80ffe5"; + tubColor = "white"; + } + roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); + + context.lineWidth = 3; + context.beginPath(); + context.moveTo(c*tileSize, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.1, c*tileSize+tileSize/3, r*tileSize+tileSize*.1, c*tileSize+tileSize/2, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.3, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.3, c*tileSize+tileSize, r*tileSize+tileSize*.2); + context.moveTo(c*tileSize, r*tileSize+tileSize*.4); + context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.3, c*tileSize+tileSize/3, r*tileSize+tileSize*.3, c*tileSize+tileSize/2, r*tileSize+tileSize*.4); + context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.5, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.5, c*tileSize+tileSize, r*tileSize+tileSize*.4); + context.moveTo(c*tileSize, r*tileSize+tileSize*.6); + context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.5, c*tileSize+tileSize/3, r*tileSize+tileSize*.5, c*tileSize+tileSize/2, r*tileSize+tileSize*.6); + context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.7, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.7, c*tileSize+tileSize, r*tileSize+tileSize*.6); + context.moveTo(c*tileSize, r*tileSize+tileSize*.8); + context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.7, c*tileSize+tileSize/3, r*tileSize+tileSize*.7, c*tileSize+tileSize/2, r*tileSize+tileSize*.8); + context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.9, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.9, c*tileSize+tileSize, r*tileSize+tileSize*.8); + context.stroke(); + + context.fillStyle = tubColor; + if(!isOccupied(-1,0)) { + if(isOccupied(-1,-1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize-tileSize*.2, tileSize*.2, tileSize*1.2, 0, true, false); + else roundRect(context, c*tileSize-tileSize*.1, r*tileSize, tileSize*.2, tileSize, 0, true, false); + } + if(!isOccupied(1,0)) roundRect(context, c*tileSize+tileSize*.9, r*tileSize, tileSize*.2, tileSize, 0, true, false); + if(!isOccupied(0,1)) { + if(isOccupied(-1,1) && !isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); + else if(!isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize*1.3, tileSize*.2, 0, true, false); + else if(isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); + else roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize, tileSize*.2, 0, true, false); + } + context.restore(); +} + + function drawLift(r, c, isFixed) { + context.lineWidth = .5; + context.strokeStyle = "#777"; + var strokeBool = false; + if(!isFixed) { + context.fillStyle = "#e68a00"; + roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); + context.fillStyle = "#cc0000"; + roundRect(context, c*tileSize+tileSize*.3, r*tileSize+tileSize*.8, tileSize*.4, tileSize*.2, {tl:2, tr:2}, true, strokeBool); + } + else if(isFixed) { + context.fillStyle = "#e68a00"; + roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize*.8, tileSize*.9, tileSize*.2, 2, true, strokeBool); + roundRect(context, c*tileSize+tileSize*.05, r*tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); + + context.fillStyle = "#333"; + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.45); + context.bezierCurveTo(c*tileSize+tileSize*.16,r*tileSize+tileSize*.45,c*tileSize+tileSize*.16,r*tileSize+tileSize*.55,c*tileSize+tileSize*.2,r*tileSize+tileSize*.55); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); + context.closePath(); + context.fill(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.45); + context.bezierCurveTo(c*tileSize+tileSize*.84,r*tileSize+tileSize*.45,c*tileSize+tileSize*.84,r*tileSize+tileSize*.55,c*tileSize+tileSize*.8,r*tileSize+tileSize*.55); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.8); + context.closePath(); + context.fill(); + + /*context.beginPath(); + context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.9); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.1); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.1); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.9); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.9); + context.closePath(); + context.fill(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.9); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.1); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.1); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.9); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.9); + context.closePath(); + context.fill();*/ + } + + /*var grd = context.createLinearGradient(c*tileSize, r*tileSize, (c+1)*tileSize, (r+1)*tileSize); + grd.addColorStop(0, "rgba(255,255,255,.6)"); + grd.addColorStop(.1, "rgba(255,255,255,.7)"); + grd.addColorStop(.2, "rgba(255,255,255,.5)"); + grd.addColorStop(.3, "rgba(255,255,255,.6)"); + grd.addColorStop(.4, "rgba(255,255,255,.8)"); + grd.addColorStop(.5, "rgba(255,255,255,.7)"); + grd.addColorStop(.6, "rgba(255,255,255,.5)"); + grd.addColorStop(.7, "rgba(255,255,255,.6)"); + grd.addColorStop(.8, "rgba(255,255,255,.7)"); + grd.addColorStop(.9, "rgba(255,255,255,.8)"); + grd.addColorStop(1, "rgba(255,255,255,.7)"); + + context.fillStyle = grd; + roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 5, true, false); + + if(!isFixed){ + var bgColor; + if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*')+2, background.length); + var r1, r2, b1, b2, g1, g2; + r1 = bgColor.substr(5, bgColor.indexOf(",")-5); + g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); + var shade = (r+1)*.03+.5; + if(shade>1) + shade = 1; + r2 = 255 + (r1-255) * shade - 20; + g2 = 255 + (g1-255) * shade - 20; + b2 = 255 + (b1-255) * shade - 20; + context.strokeStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; + //context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.5, r*tileSize); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.15); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.4); + context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.35); + context.stroke(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.4); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.5); + context.stroke(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.7); + context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.55, r*tileSize+tileSize*.9); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*1); + context.stroke(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.7); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*1); + context.stroke(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.35); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.8); + context.stroke(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.35); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.1); + context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize); + context.stroke(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.35); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); + context.lineTo(c*tileSize+tileSize*.55, r*tileSize+tileSize*.45); + context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.6); + context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.7); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.15, r*tileSize+tileSize*.7); + context.lineTo(c*tileSize+tileSize*.02, r*tileSize+tileSize*.98); + context.stroke(); + + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.35); + context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.25); + context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.2); + context.stroke(); + }*/ + } + + function drawWall(r, c, adjacentTiles) { //GOOBY + //drawRect(r, c, "#976537"); + drawTileNew(r, c, isWall, 0.2, material); + drawTileOutlines(r, c, isWall, 0.2, curlyOutline); + context.save(); + if(curlyOutline) drawBushes(r, c, isWall); + context.restore(); + context.fillStyle = "#895C33"; // dirt edge + //drawTileOutlines(r, c, isWall, 0.2, false); + + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } + } + + function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle){ + context.fillStyle = fillStyle; + if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10,br:10}, true, false); + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10}, true, false); + else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {br:10}, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); + else roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); + + /*var randomSpot = Math.floor(Math.random() * 5); //random spots on dirt + var randomColor = Math.floor(Math.random() * 5); + context.beginPath(); + switch(randomSpot){ + case 0: + context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 5, 0, 2*Math.PI); + case 1: + context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 4, 0, 2*Math.PI); + case 2: + context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 3, 0, 2*Math.PI); + case 3: + context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 2, 0, 2*Math.PI); + case 4: + context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 1, 0, 2*Math.PI); + } + context.stroke();*/ + } + + function drawCurves(r, c, adjacentTiles){ + drawCurves2(r, c, isWall, material); + + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } + } + + function drawCurves2(r, c, isOccupied, material){ + context.fillStyle = material; + if(isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { + context.fillRect((c+1)*tileSize, (r+1)*tileSize, tileSize/6, tileSize/6); + //context.globalCompositeOperation = "destination-out"; + context.beginPath(); + context.arc((c+1)*tileSize+tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); + context.closePath(); + + var bgColor; + if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*')+2, background.length); + var r1, r2, b1, b2, g1, g2; + r1 = bgColor.substr(5, bgColor.indexOf(",")-5); + g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); + var shade = (r+1)*.03+.5; + if(shade>1) + shade = 1; + r2 = 255 + (r1-255) * shade; + g2 = 255 + (g1-255) * shade; + b2 = 255 + (b1-255) * shade; + context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; + context.fill(); + context.globalCompositeOperation = "source-over"; + } + if(isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1) && curlyOutline) { + context.fillRect(c*tileSize-tileSize/6, (r+1)*tileSize, tileSize/6, tileSize/6); + //context.globalCompositeOperation = "destination-out"; + context.beginPath(); + context.arc(c*tileSize-tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); + context.closePath(); + + var bgColor; + if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*')+2, background.length); + var r1, r2, b1, b2, g1, g2; + r1 = bgColor.substr(5, bgColor.indexOf(",")-5); + g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); + var shade = (r+1)*.03+.5; + if(shade>1) + shade = 1; + r2 = 255 + (r1-255) * shade; + g2 = 255 + (g1-255) * shade; + b2 = 255 + (b1-255) * shade; + context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; + context.fill(); + context.globalCompositeOperation = "source-over"; + } + } + + function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { //Gooby + if(surface != "rainbow") { + context.fillStyle = surface; + } + else{ + context.fillStyle = "white"; + var mod = (r+c) % 17; + switch(mod){ + case 0: context.fillStyle = "#ff004c"; break; + case 1: context.fillStyle = "#e30000"; break; + case 2: context.fillStyle = "#ff4c00"; break; + case 3: context.fillStyle = "#ff9900"; break; + case 4: context.fillStyle = "#ffe500"; break; + case 5: context.fillStyle = "#cbff00"; break; + case 6: context.fillStyle = "#7fff00"; break; + case 7: context.fillStyle = "#00ff19"; break; + case 8: context.fillStyle = "#00ff66"; break; + case 9: context.fillStyle = "#00ffb2"; break; + case 10: context.fillStyle = "#00ffff"; break; + case 11: context.fillStyle = "#00b2ff"; break; + case 12: context.fillStyle = "#3200ff"; break; + case 13: context.fillStyle = "#5702c6"; break; + case 14: context.fillStyle = "#cc00ff"; break; + case 15: context.fillStyle = "#ff00e5"; break; + case 16: context.fillStyle = "#ff0098"; break; + } + } + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + var complementPixels = (1 - 2 * outlineThickness) * tileSize; + + if (curlyOutline && !isOccupied(0, -1)){ + if(!isOccupied(-1, 0) && isOccupied(1, 0)){ + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.4, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize, r*tileSize); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize); + context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); + context.closePath(); + } + else if(isOccupied(-1, 0) && !isOccupied(1, 0)){ + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.95, r*tileSize+tileSize*.3, c*tileSize+tileSize*.7, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.65, r*tileSize+tileSize*.4, c*tileSize+tileSize*.4, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.1, r*tileSize+tileSize*.4, c*tileSize, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize); + context.bezierCurveTo((c+1)*tileSize+tileSize*.2, r*tileSize-tileSize*.05, (c+1)*tileSize+tileSize*.15, r*tileSize+tileSize*.5, (c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.25); + context.closePath(); + } + else if(!isOccupied(-1, 0) && !isOccupied(1, 0)){ + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.9, r*tileSize-tileSize*0); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize); + context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); + context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.8, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); + context.bezierCurveTo((c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.4, (c+1)*tileSize+tileSize*.3, r*tileSize+tileSize*.3, (c+1)*tileSize, r*tileSize+tileSize*.02); + context.closePath(); + } + else{ + context.beginPath(); + context.moveTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize, r*tileSize+tileSize*.15); + context.bezierCurveTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.4, c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.3, c*tileSize+tileSize*.6, r*tileSize+tileSize*.3, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize, r*tileSize); + context.closePath(); + } + context.fill(); + } + else if(!curlyOutline && !isOccupied(0, -1)){ context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + + } + if (!curlyOutline && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); + if (!curlyOutline && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!curlyOutline && !isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); + } + + function drawBushes(r, c, isOccupied){ + if(!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)){ + /*context.shadowColor = "#666"; + context.shadowOffsetX = -.5; + context.shadowOffsetY = -.5; + context.shadowBlur = 1;*/ + + context.beginPath(); + context.moveTo((c+1)*tileSize, r*tileSize); + context.lineTo((c+1)*tileSize, r*tileSize-tileSize*.4); + context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); + context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); + context.lineTo((c+1)*tileSize, r*tileSize); + context.closePath(); + context.fill(); + + context.beginPath(); + context.moveTo((c+1)*tileSize, r*tileSize-tileSize*.4); + context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); + context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); + } + + if(!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)){ + /*context.shadowColor = "#666"; + context.shadowOffsetX = .5; + context.shadowOffsetY = -.5; + context.shadowBlur = 1;*/ + + context.beginPath(); + context.moveTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize, r*tileSize-tileSize*.4); + context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); + context.lineTo(c*tileSize, r*tileSize); + context.closePath(); + context.fill(); + + context.restore(); + + context.beginPath(); + context.moveTo(c*tileSize, r*tileSize-tileSize*.4); + context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); + /*context.strokeStyle = "#7dff1a"; + context.stroke();*/ + } + } + + function drawSpikes(r, c, adjacentTiles) { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = spikeColors[0]; + + context.beginPath(); + context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes + context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.45, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.55, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.75, y + tileSize * 0.3); + + context.moveTo(x + tileSize * 0.7, y + tileSize * 0.25); //right spikes + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.45); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.55); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.75); + + context.moveTo(x + tileSize * 0.75, y + tileSize * 0.7); //bottom spikes + context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.55, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.45, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.25, y + tileSize * 0.7); + + context.moveTo(x + tileSize * 0.3, y + tileSize * 0.75); //left spikes + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.55); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.45); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); + context.closePath(); + + /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ + context.fill(); + drawSpikeSupports(r, c, isSpike, isWall); + + function isSpike(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === SPIKE; + } + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } + } + + function drawSpikeSupports(r, c, isOccupied, canConnect){ + var boltBool = false; + var occupiedCount = 0; + if(canConnect(0, 1)){ + context.fillStyle = spikeColors[1]; + context.fillRect(c*tileSize+(tileSize*.3), r*tileSize+(tileSize*.8), tileSize*.4, tileSize*.4); + boltBool = true; + } + if(canConnect(0, -1) && !canConnect(0, 1)){ + if(!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(1, -1)){} + else{ + context.fillStyle = spikeColors[1]; + context.fillRect(c*tileSize+(tileSize*.3), r*tileSize, tileSize*.4, tileSize*.4); + boltBool = true; + } + } + if(canConnect(-1, 0) && !canConnect(0, 1)){ + if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(-1, 1)){} + else{ + context.fillStyle = spikeColors[1]; + context.fillRect(c*tileSize, r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); + boltBool = true; + } + } + if(canConnect(1, 0) && !canConnect(0, 1)){ + if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(1, -1) && canConnect(1, 1)){} + else{ + context.fillStyle = spikeColors[1]; + context.fillRect(c*tileSize+(tileSize*.8), r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); + boltBool = true; + } + } + + context.fillStyle = spikeColors[2]; + if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING ONE + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4,br:4}, true, false); + boltBool = true; + } + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize, tileSize*.6, {tl:4,bl:4}, true, false); + boltBool = true; + } + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4,tr:4}, true, false); + boltBool = true; + } + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4,br:4}, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (CORNERS) + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4}, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {bl:4}, true, false); + if(!canConnect(1, -1)) boltBool = true; + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {br:4}, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {br:4}, true, false); + if(!canConnect(-1, -1)) boltBool = true; + } + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tl:4}, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4}, true, false); + if(!canConnect(1, 1)) boltBool = true; + } + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4}, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tr:4}, true, false); + if(!canConnect(-1, 1)) boltBool = true; + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (OPPOSITES) + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + } + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING THREE + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, 0, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); + boltBool = true; + } + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, 0, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ //TOUCHING FOUR + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + //boltBool = true; + } + else{ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.6, 0, true, false); + boltBool = true; + } + + if (boltBool) drawBolt(r, c); + } + + function drawBolt(r, c){ + context.strokeStyle = spikeColors[3]; + context.beginPath(); + context.arc(c*tileSize+(tileSize*.55), r*tileSize+(tileSize*.45), 4, -.7*Math.PI, .2*Math.PI); + context.lineTo(c*tileSize+(tileSize*.45),r*tileSize+(tileSize*.35)); + context.closePath(); + context.fillStyle = spikeColors[3]; + context.fill(); + context.stroke(); + + context.beginPath(); + context.moveTo(c*tileSize+(tileSize*.43),r*tileSize+(tileSize*.47)); + context.arc(c*tileSize+(tileSize*.48), r*tileSize+(tileSize*.52), 4, .2*Math.PI, -.75*Math.PI); + //context.lineTo(c*tileSize+(tileSize*.4),r*tileSize+(tileSize*.6)); + context.closePath(); + context.fillStyle = spikeColors[3]; + context.fill(); + context.stroke(); + } + + function drawConnector(context, r1, c1, r2, c2, color) { + // either r1 and r2 or c1 and c2 must be equal + if (r1 > r2 || c1 > c2) { + var rTmp = r1; + var cTmp = c1; + r1 = r2; + c1 = c2; + r2 = rTmp; + c2 = cTmp; + } + var xLo = (c1 + 0.3) * tileSize; + var yLo = (r1 + 0.3) * tileSize; + var xHi = (c2 + 0.45) * tileSize; + var yHi = (r2 + 0.45) * tileSize; + context.fillStyle = color; + context.fillRect(xLo+.15*tileSize, yLo+.15*tileSize, xHi - xLo, yHi - yLo); + } + function drawBlock(block) { + var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); + var rowcols = block.locations.map(function(location) { + return getRowcol(level, location); + }); + rowcols.forEach(function(rowcol) { + var r = rowcol.r + animationDisplacementRowcol.r; + var c = rowcol.c + animationDisplacementRowcol.c; + context.fillStyle = blockColors[0][block.id % blockColors[0].length]; + var outlineThickness = .2; + + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + if (!isAlsoThisBlock(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + if (!isAlsoThisBlock( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); + if (!isAlsoThisBlock(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!isAlsoThisBlock( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); + + function isAlsoThisBlock(dc, dr) { + for (var i = 0; i < rowcols.length; i++) { + var otherRowcol = rowcols[i]; + if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; + } + return false; + } + }); + } + function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { + var cx = (c + 0.5) * tileSize; + var cy = (r + 0.5) * tileSize; + context.fillStyle = fillStyle; + context.beginPath(); + context.moveTo(cx, cy); + context.arc(cx, cy, radiusFactor * tileSize/2, quadrant * Math.PI/2, (quadrant + 1) * Math.PI/2); + context.fill(); + } + function drawDiamond(r, c, fillStyle) { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = fillStyle; + roundRect(context, x, y, tileSize, tileSize, 10, true, false); + } + function drawCircle(r, c, radiusFactor, fillStyle) { + context.fillStyle = fillStyle; + context.beginPath(); + context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize/2 * radiusFactor, 0, 2*Math.PI); + context.fill(); + } + function drawRect(r, c, fillStyle) { + context.fillStyle = fillStyle; + context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); + } + + function drawCloud(c, x, y){ + c.fillStyle = experimentalColors[0]; + /*c.beginPath(); + c.rect(x, y, tileSize, tileSize); + c.fill(); + c.closePath();*/ + + c.beginPath(); + c.moveTo(x+tileSize*0, y+tileSize*0); + + c.bezierCurveTo(x+tileSize*0, y-tileSize*.15, x+tileSize*.33, y-tileSize*.15, x+tileSize*.33, y+tileSize*0); + c.bezierCurveTo(x+tileSize*.33, y-tileSize*.15, x+tileSize*.67, y-tileSize*.15, x+tileSize*.67, y+tileSize*0); + c.bezierCurveTo(x+tileSize*.67, y-tileSize*.15, x+tileSize*1, y-tileSize*.15, x+tileSize*1, y+tileSize*0); + + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*0, x+tileSize*1.15, y+tileSize*.33, x+tileSize*1, y+tileSize*.33); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.33, x+tileSize*1.15, y+tileSize*.67, x+tileSize*1, y+tileSize*.67); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.67, x+tileSize*1.15, y+tileSize*1, x+tileSize*1, y+tileSize*1); + + c.bezierCurveTo(x+tileSize*1, y+tileSize*1.15, x+tileSize*.67, y+tileSize*1.15, x+tileSize*.67, y+tileSize*1); + c.bezierCurveTo(x+tileSize*.67, y+tileSize*1.15, x+tileSize*.33, y+tileSize*1.15, x+tileSize*.33, y+tileSize*1); + c.bezierCurveTo(x+tileSize*.33, y+tileSize*1.15, x+tileSize*0, y+tileSize*1.15, x+tileSize*0, y+tileSize*1); + + c.bezierCurveTo(x-tileSize*.15, y+tileSize*1, x-tileSize*.15, y+tileSize*.67, x+tileSize*0, y+tileSize*.67); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*.67, x-tileSize*.15, y+tileSize*.33, x+tileSize*0, y+tileSize*.33); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*.33, x-tileSize*.15, y+tileSize*0, x+tileSize*0, y+tileSize*0); + + c.closePath(); + c.fill(); + //c.stroke(); + } + +function drawFace(snake, headCol, headRow, orientation){ + var x = headCol * tileSize; + var y = headRow * tileSize; + + var scaleFactor = 1.5; + var scale1; + var scale2; + var eye1 = tileSize*.8; + var eye2 = tileSize*.4; + + var eyeSize = tileSize/5; + var eyeRotation = 2; + var z1, z2, z3, z4, z5, z6, z7, z8; + var a1, a2, a3, a4, a5, a6, a7, a8; + var beakRotation = 1.5; + var arcDirection = false; + + switch(orientation){ + case 0: //red up and blue left + z1 = eye2; + z2 = tileSize-eye1; + z3 = eye2; + z4 = tileSize-eye2; + z5 = eye2; + z6 = tileSize-eye1; + z7 = eye2; + z8 = tileSize-eye2 + eyeRotation = 1.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize*.7; + a2 = tileSize-tileSize*.7; + a3 = tileSize*.7; + a4 = -tileSize*.3; + a5 = tileSize*.7; + a6 = tileSize*.3; + a7 = tileSize/6; + a8 = 0; + beakRotation = 1; + arcDirection = false; + break; + case 1: //red right and blue up + z1 = eye1; + z2 = eye2; + z3 = eye2; + z4 = eye2; + z5 = eye1; + z6 = eye2; + z7 = eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize*1.3; + a4 = tileSize*.7; + a5 = tileSize*.7; + a6 = tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = false; + break; + case 2: //red down and blue right + z1 = tileSize-eye2; + z2 = eye1; + z3 = tileSize-eye2; + z4 = eye2; + z5 = tileSize-eye2; + z6 = eye1; + z7 = tileSize-eye2; + z8 = eye2; + eyeRotation = 2.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize-tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize-tileSize*.7; + a4 = tileSize*1.3; + a5 = tileSize-tileSize*.7; + a6 = tileSize*.7; + a7 = tileSize/6; + a8 = 0; + beakRotation = 1; + arcDirection = true; + break; + case 3: //red left and blue down + z1 = tileSize-eye1; + z2 = tileSize-eye2; + z3 = tileSize-eye2; + z4 = tileSize-eye2; + z5 = tileSize-eye1; + z6 = tileSize-eye2; + z7 = tileSize-eye2; + z8 = tileSize-eye2; + eyeRotation = 3; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize-tileSize*.7; + a2 = tileSize-tileSize*.7; + a3 = tileSize-tileSize*1.3; + a4 = tileSize-tileSize*.7; + a5 = tileSize-tileSize*.7; + a6 = tileSize-tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = true; + break; + case 4: //green up and yellow right + z1 = tileSize-eye2; + z2 = tileSize-eye1; + z3 = tileSize-eye2; + z4 = tileSize-eye2; + z5 = tileSize-eye2; + z6 = tileSize-eye1; + z7 = tileSize-eye2; + z8 = tileSize-eye2 + eyeRotation = 2.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize-tileSize*.7; + a2 = tileSize-tileSize*.7; + a3 = tileSize-tileSize*.7; + a4 = -tileSize*.3; + a5 = tileSize-tileSize*.7; + a6 = tileSize*.3; + a7 = tileSize/6; + a8 = 0; + beakRotation = 1; + arcDirection = false; + break; + case 5: //green right and yellow down + z1 = eye1; + z2 = tileSize-eye2; + z3 = eye2; + z4 = tileSize-eye2; + z5 = eye1; + z6 = tileSize-eye2; + z7 = eye2; + z8 = tileSize-eye2; + eyeRotation = 3; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize*.7; + a2 = tileSize-tileSize*.7; + a3 = tileSize*1.3; + a4 = tileSize-tileSize*.7; + a5 = tileSize*.7; + a6 = tileSize-tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = false; + break; + case 6: //green down and yellow left + z1 = eye2; + z2 = eye1; + z3 = eye2; + z4 = eye2; + z5 = eye2; + z6 = eye1; + z7 = eye2; + z8 = eye2; + eyeRotation = 1.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize*.7; + a4 = tileSize*1.3; + a5 = tileSize*.7; + a6 = tileSize*.7; + a7 = tileSize/6; + a8 = 0; + beakRotation = 1; + arcDirection = true; + break; + case 7: //green left and yellow up + z1 = tileSize-eye1; + z2 = eye2; + z3 = tileSize-eye2; + z4 = eye2; + z5 = tileSize-eye1; + z6 = eye2; + z7 = tileSize-eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize-tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize-tileSize*1.3; + a4 = tileSize*.7; + a5 = tileSize-tileSize*.7; + a6 = tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = true; + break; + case 10: //single unit snake + z1 = eye1; + z2 = eye2; + z3 = eye2; + z4 = eye2; + z5 = eye1; + z6 = eye2; + z7 = eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize*1.3; + a4 = tileSize*.7; + a5 = tileSize*.7; + a6 = tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = false; + break; + } + + if (snake === activeSnakeId) { //draw eyes for active snake only + context.fillStyle = "white"; + context.save(); + context.scale(scale1,scale2); + context.beginPath(); + context.arc((x+z1)/scale1, (y+z2)/scale2, eyeSize, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + + context.fillStyle = "white"; + context.save(); + context.scale(scale1,scale2); + context.beginPath(); + context.arc((x+z3)/scale1, (y+z4)/scale2, eyeSize, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + + context.fillStyle = "black"; + context.save(); + context.scale(scale1,scale2); + context.beginPath(); + context.arc((x+z5)/scale1, (y+z6)/scale2, eyeSize/2, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + + context.fillStyle = "black"; + context.save(); + context.scale(scale1,scale2); + context.beginPath(); + context.arc((x+z7)/scale1, (y+z8)/scale2, eyeSize/2, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + } + + //beak + context.fillStyle = "#F9921C"; + context.beginPath(); + context.arc(x+a1, y+a2, tileSize/6, (beakRotation-1)*Math.PI, beakRotation*Math.PI, arcDirection); + context.lineTo(x+a3, y+a4); + context.lineTo(x+a5+a7, y+a6+a8); + context.closePath(); + context.fill(); +} + + function roundRect(ctx, x, y, width, height, radius, fill, stroke) { //Gooby + if (typeof stroke === 'undefined') { + stroke = true; + } + if (typeof radius === 'undefined') { + radius = 5; + } + if (typeof radius === 'number') { + radius = {tl: radius, tr: radius, br: radius, bl: radius}; + } else { + var defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0}; + for (var side in defaultRadius) { + radius[side] = radius[side] || defaultRadius[side]; + } + } + ctx.beginPath(); + ctx.moveTo(x + radius.tl, y); + ctx.lineTo(x + width - radius.tr, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); + ctx.lineTo(x + width, y + height - radius.br); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); + ctx.lineTo(x + radius.bl, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl); + ctx.lineTo(x, y + radius.tl); + ctx.quadraticCurveTo(x, y, x + radius.tl, y); + ctx.closePath(); + if (fill) { + ctx.fill(); + } + if (stroke) { + ctx.stroke(); + } + } + +function shadeColor(color, percent) { + + var R = parseInt(color.substring(1,3),16); + var G = parseInt(color.substring(3,5),16); + var B = parseInt(color.substring(5,7),16); + + R = parseInt(R * (100 + percent) / 100); + G = parseInt(G * (100 + percent) / 100); + B = parseInt(B * (100 + percent) / 100); + + R = (R<255)?R:255; + G = (G<255)?G:255; + B = (B<255)?B:255; + + var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16)); + var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16)); + var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16)); + + return "#"+RR+GG+BB; +} + + + function drawR(r,c,fillStyle){ //Gooby + context.fillStyle = fillStyle; + var cornerRadius = 20; + context.lineJoin = "round"; + context.lineWidth = 1; + context.strokeRect(c*tileSize, r*tileSize, tileSize, tileSize); + //context.fillRect(c*tileSize, r*tileSize, tileSize, tileSize); + } + + function drawGrid() { + var buffer = document.createElement("canvas"); + buffer.width = canvas.width; + buffer.height = canvas.height; + var localContext = buffer.getContext("2d"); + + localContext.strokeStyle = "#fff"; + localContext.beginPath(); + for (var r = 0; r < level.height; r++) { + localContext.moveTo(0, tileSize*r); + localContext.lineTo(tileSize*level.width, tileSize*r); + } + for (var c = 0; c < level.width; c++) { + localContext.moveTo(tileSize*c, 0); + localContext.lineTo(tileSize*c, tileSize*level.height); + } + localContext.stroke(); + + context.save(); + context.globalAlpha = 0.4; + context.drawImage(buffer, 0, 0); + context.restore(); + } +} + +function findAnimation(animationTypes, objectId) { + if (animationQueueCursor === animationQueue.length) return null; + var currentAnimation = animationQueue[animationQueueCursor]; + for (var i = 1; i < currentAnimation.length; i++) { + var animation = currentAnimation[i]; + if (animationTypes.indexOf(animation[0]) !== -1 && animation[1] === objectId) return animation; + } +} +function findAnimationDisplacementRowcol(objectType, objectId) { + var dr = 0; + var dc = 0; + var animationTypes = [ + "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK + "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK + ]; + // skip the current one + for (var i = animationQueueCursor + 1; i < animationQueue.length; i++) { + var animations = animationQueue[i]; + for (var j = 1; j < animations.length; j++) { + var animation = animations[j]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === objectId) { + dr += animation[2]; + dc += animation[3]; + } + } + } + var movementAnimation = findAnimation(animationTypes, objectId); + if (movementAnimation != null) { + dr += movementAnimation[2] * (1 - animationProgress); + dc += movementAnimation[3] * (1 - animationProgress); + } + return {r: -dr, c: -dc}; +} +function hasFutureRemoveAnimation(object) { + var animationTypes = [ + EXIT_SNAKE, + DIE_BLOCK, + ]; + for (var i = animationQueueCursor; i < animationQueue.length; i++) { + var animations = animationQueue[i]; + for (var j = 1; j < animations.length; j++) { + var animation = animations[j]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === object.id) { + return true; + } + } + } +} + +function previewPaste(hoverR, hoverC) { + var offsetR = hoverR - clipboardOffsetRowcol.r; + var offsetC = hoverC - clipboardOffsetRowcol.c; + + var newLevel = JSON.parse(JSON.stringify(level)); + var selectedLocations = []; + var selectedObjects = []; + clipboardData.selectedLocations.forEach(function(location) { + var tileCode = clipboardData.level.map[location]; + var rowcol = getRowcol(clipboardData.level, location); + var r = rowcol.r + offsetR; + var c = rowcol.c + offsetC; + if (!isInBounds(newLevel, r, c)) return; + var newLocation = getLocation(newLevel, r, c); + newLevel.map[newLocation] = tileCode; + selectedLocations.push(newLocation); + }); + clipboardData.selectedObjects.forEach(function(object) { + var newLocations = []; + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(clipboardData.level, object.locations[i]); + rowcol.r += offsetR; + rowcol.c += offsetC; + if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { + // this location is oob + if (object.type === SNAKE) { + // snakes must be completely in bounds + return; + } + // just skip it + continue; + } + var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); + newLocations.push(newLocation); + } + if (newLocations.length === 0) return; // can't have a non-present object + var newObject = JSON.parse(JSON.stringify(object)); + newObject.locations = newLocations; + selectedObjects.push(newObject); + }); + return { + level: newLevel, + selectedLocations: selectedLocations, + selectedObjects: selectedObjects, + }; +} + +function getNaiveOrthogonalPath(a, b) { + // does not include a, but does include b. + var rowcolA = getRowcol(level, a); + var rowcolB = getRowcol(level, b); + var path = []; + if (rowcolA.r < rowcolB.r) { + for (var r = rowcolA.r; r < rowcolB.r; r++) { + path.push(getLocation(level, r + 1, rowcolA.c)); + } + } else { + for (var r = rowcolA.r; r > rowcolB.r; r--) { + path.push(getLocation(level, r - 1, rowcolA.c)); + } + } + if (rowcolA.c < rowcolB.c) { + for (var c = rowcolA.c; c < rowcolB.c; c++) { + path.push(getLocation(level, rowcolB.r, c + 1)); + } + } else { + for (var c = rowcolA.c; c > rowcolB.c; c--) { + path.push(getLocation(level, rowcolB.r, c - 1)); + } + } + return path; +} +function identityFunction(x) { + return x; +} +function compareId(a, b) { + return operatorCompare(a.id, b.id); +} +function operatorCompare(a, b) { + return a < b ? -1 : a > b ? 1 : 0; +} +function clamp(value, min, max) { + if (value < min) return min; + if (value > max) return max; + return value; +} +function copyArray(array) { + return array.map(identityFunction); +} +function getSetIntersection(array1, array2) { + if (array1.length * array2.length === 0) return []; + return array1.filter(function(x) { return array2.indexOf(x) !== -1; }); +} +function makeScaleCoordinatesFunction(width1, width2) { + return function(location) { + return location + (width2 - width1) * Math.floor(location / width1); + }; +} + +var expectHash; +window.addEventListener("hashchange", function() { + if (location.hash === expectHash) { + // We're in the middle of saveLevel() or saveReplay(). + // Don't react to that event. + expectHash = null; + return; + } + // The user typed into the url bar or used Back/Forward browser buttons, etc. + loadFromLocationHash(); +}); +function loadFromLocationHash() { + var hashSegments = location.hash.split("#"); + hashSegments.shift(); // first element is always "" + if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; + var hashPairs = hashSegments.map(function(segment) { + var equalsIndex = segment.indexOf("="); + if (equalsIndex === -1) return ["", segment]; // bad + return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; + }); + + if (hashPairs[0][0] !== "level") return false; + try { + var level = parseLevel(hashPairs[0][1]); + } catch (e) { + alert(e); + return false; + } + loadLevel(level); + if (hashPairs.length > 1) { + try { + if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); + parseAndLoadReplay(hashPairs[1][1]); + } catch (e) { + alert(e); + return false; + } + } + return true; +} + +// run test suite +var testTime = new Date().getTime(); +if (compressSerialization(stringifyLevel(parseLevel(testLevel_v0))) !== testLevel_v0_converted) throw new Error("v0 level conversion is broken"); +// ask the debug console for this variable if you're concerned with how much time this wastes. +testTime = new Date().getTime() - testTime; + +loadPersistentState(); +if (!loadFromLocationHash()) { + loadLevel(parseLevel(exampleLevel)); +} From 665936be0029ba8622c7cae756bfc38ca0ba0117 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 18 Feb 2020 17:08:44 -0500 Subject: [PATCH 279/577] Update and rename SolutionVerification to SolutionVerification.html --- SolutionVerification => SolutionVerification.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename SolutionVerification => SolutionVerification.html (98%) diff --git a/SolutionVerification b/SolutionVerification.html similarity index 98% rename from SolutionVerification rename to SolutionVerification.html index 96f31d8a..98615645 100644 --- a/SolutionVerification +++ b/SolutionVerification.html @@ -43,6 +43,6 @@
    - + From d244979b76918a212b524c0ef9da4cc05dad8bfb Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 18 Feb 2020 17:08:50 -0500 Subject: [PATCH 280/577] Rename SV.js to SolutionVerification.js --- SV.js => SolutionVerification.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename SV.js => SolutionVerification.js (100%) diff --git a/SV.js b/SolutionVerification.js similarity index 100% rename from SV.js rename to SolutionVerification.js From 0959d96c8dd472670c84d06f7c315fc959838610 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Tue, 18 Feb 2020 17:11:48 -0500 Subject: [PATCH 281/577] Update index.html --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 3099b29d..5afc9a6d 100644 --- a/index.html +++ b/index.html @@ -199,7 +199,7 @@ - + Floating Fruits XeroOl @@ -396,7 +396,7 @@ - Serpentine + Serpentine Collaboration Created by Gooby & Joel Fox @@ -562,7 +562,7 @@ - Underground + Cloud 9 Gooby From 3ecfc78b4bdb14d2d2f2eb4bf5da62c96cdbb44b Mon Sep 17 00:00:00 2001 From: Patashu Date: Wed, 19 Feb 2020 15:22:09 +1100 Subject: [PATCH 282/577] Implement Poison Fruit Poison Fruit is like Fruit in all respects (including locking the portal), except it shrinks a snake instead of grows a snake. A snake that shrinks to 0 causes game over. --- Framework.html | 4 +++ Main.js | 76 ++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 68 insertions(+), 12 deletions(-) diff --git a/Framework.html b/Framework.html index e81db58b..55bc57b2 100644 --- a/Framework.html +++ b/Framework.html @@ -54,6 +54,10 @@ Liquids + + + Moveables + diff --git a/Main.js b/Main.js index ea1d39a8..0c7bab28 100644 --- a/Main.js +++ b/Main.js @@ -41,6 +41,7 @@ var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, var SNAKE = "s"; var BLOCK = "b"; var FRUIT = "f"; +var POISON_FRUIT = "p"; var headRowMove; var headColMove; @@ -163,7 +164,7 @@ function parseLevel(string) { var locationsLimit; if (object.type === SNAKE) locationsLimit = -1; else if (object.type === BLOCK) locationsLimit = -1; - else if (object.type === FRUIT) locationsLimit = 1; + else if (object.type === FRUIT || object.type === POISON_FRUIT) locationsLimit = 1; else throw parserError("expected object type code"); cursor += 1; @@ -538,6 +539,7 @@ document.addEventListener("keydown", function(event) { case "P".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(POISON_FRUIT); break; } return; case "U".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } @@ -695,6 +697,7 @@ var paintButtonIdAndTileCodes = [ ["paintSpikeButton", SPIKE], ["paintExitButton", EXIT], ["paintFruitButton", FRUIT], + ["paintPoisonFruitButton", POISON_FRUIT], ["paintPortalButton", PORTAL], ["paintPlatformButton", PLATFORM], ["paintWoodPlatformButton", WOODPLATFORM], @@ -816,7 +819,11 @@ canvas.addEventListener("dblclick", function(event) { } else if (object.type === FRUIT) { // edit fruits, i guess paintBrushTileCode = FRUIT; - } else throw unreachable(); + } else if (object.type === POISON_FRUIT) { + // edit poison fruits, i guess + paintBrushTileCode = POISON_FRUIT; + } + else throw unreachable(); paintBrushTileCodeChanged(); } }); @@ -1157,6 +1164,19 @@ function newFruit(location) { locations: [location], }; } +function newPoisonFruit(location) { + var fruits = getObjectsOfType(POISON_FRUIT); + fruits.sort(compareId); + for (var i = 0; i < fruits.length; i++) { + if (fruits[i].id !== i) break; + } + return { + type: POISON_FRUIT, + id: i, + dead: false, // unused + locations: [location], + }; +} function paintAtLocation(location, changeLog) { if (typeof paintBrushTileCode === "number") { removeAnyObjectAtLocation(location, changeLog); @@ -1186,6 +1206,8 @@ function paintAtLocation(location, changeLog) { object.id = newBlock().id; } else if (object.type === FRUIT) { object.id = newFruit().id; + } else if (object.type === POISON_FRUIT) { + object.id = newPoisonFruit().id; } else throw unreachable(); level.objects.push(object); changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); @@ -1256,10 +1278,10 @@ function paintAtLocation(location, changeLog) { changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); delete blockSupportRenderCache[thisBlock.id]; } - } else if (paintBrushTileCode === FRUIT) { + } else if (paintBrushTileCode === FRUIT || paintBrushTileCode === POISON_FRUIT) { paintTileAtLocation(location, SPACE, changeLog); removeAnyObjectAtLocation(location, changeLog); - var object = newFruit(location) + var object = paintBrushTileCode == FRUIT ? newFruit(location) : newPoisonFruit(location); level.objects.push(object); changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); } else throw unreachable(); @@ -1359,7 +1381,7 @@ function reduceChangeLog(changeLog) { changeLog.splice(i, 1); i--; } - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { for (var j = i + 1; j < changeLog.length; j++) { var otherChange = changeLog[j]; if (otherChange[0] === change[0] && otherChange[1] === change[1]) { @@ -1507,7 +1529,7 @@ function undoChanges(changes, changeLog) { if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; paintTileAtLocation(location, fromTileCode, changeLog); - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { // change object var type = change[0]; var id = change[1]; @@ -1595,6 +1617,9 @@ function describe(arg1, arg2) { if (arg1 === FRUIT) { return "Fruit"; } + if (arg1 === POISON_FRUIT) { + return "Poison Fruit"; + } if (typeof arg1 === "object") return describe(arg1.type, arg1.id); throw unreachable(); } @@ -1793,6 +1818,7 @@ function move(dr, dc) { } var ate = false; + var ate_poison = false; var pushedObjects = []; //track ClosedLifts that had objects on them @@ -1810,6 +1836,10 @@ function move(dr, dc) { // eat removeObject(otherObject, changeLog); ate = true; + } else if (otherObject.type === POISON_FRUIT) { + // eat poison + removeObject(otherObject, changeLog); + ate_poison = true; } else if (isTileCodeAir(activeSnake, null, newTile, dr, dc)) { otherObject = findObjectAtLocation(newLocation); if (otherObject != null) { @@ -1835,7 +1865,21 @@ function move(dr, dc) { ] ]; activeSnake.locations.unshift(newLocation); - if (!ate) { + + // drag your tail forward based on what was/wasn't eaten + var times = 1; + if (ate) { times--; } + if (ate_poison) { times++; } + //if we're going to shrink out of existence, prevent it + var snake_length = activeSnake.locations.length-1; + if (times > snake_length) + { + times = snake_length; + activeSnake.dead = true; + //make the snake appear to vanish into non-existence + activeSnake.locations[0] = {r:-99, c:-99}; + } + for (var t = 0; t < times; ++t) { for(var i = 1; i 0; + return getObjectsOfType(FRUIT).length > 0 || getObjectsOfType(POISON_FRUIT).length > 0; } function getActivePortalLocations() { var portalLocations = getPortalLocations(); @@ -2530,7 +2574,7 @@ function render() { for(var i = 0; i Date: Wed, 19 Feb 2020 16:27:28 -0500 Subject: [PATCH 283/577] Update Framework.html --- Framework.html | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/Framework.html b/Framework.html index 55bc57b2..c66aead8 100644 --- a/Framework.html +++ b/Framework.html @@ -1,7 +1,7 @@ Snakefall Redesign - + @@ -40,7 +40,7 @@ Experimental Elements Removeables - + Scissor Lifts @@ -50,15 +50,6 @@ Platforms - - - Liquids - - - - Moveables - - From e1bae33af73a1c02cada2c0479bd77b1fc163ed1 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 19 Feb 2020 16:27:40 -0500 Subject: [PATCH 284/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index c66aead8..34b33a4c 100644 --- a/Framework.html +++ b/Framework.html @@ -1,7 +1,7 @@ Snakefall Redesign - + From 3d67bddeefc37b456a827ba3bc79cf89109d72c4 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 19 Feb 2020 16:39:08 -0500 Subject: [PATCH 285/577] Update Main.js --- Main.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Main.js b/Main.js index 0c7bab28..c59f9fb9 100644 --- a/Main.js +++ b/Main.js @@ -527,6 +527,7 @@ document.addEventListener("keydown", function(event) { return; case "F".charCodeAt(0): if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(POISON_FRUIT); break; } return; case "D".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } @@ -539,7 +540,6 @@ document.addEventListener("keydown", function(event) { case "P".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(POISON_FRUIT); break; } return; case "U".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } @@ -2922,7 +2922,8 @@ function getTintedColor(color, v) { var startR = r*tileSize+tileSize*.2; var resize = tileSize * 1.7; var color = fruitColors[object.id % fruitColors.length]; - if (is_poison) { color = "#556815"; } //placeholder effect + var stemColor = themes[themeCounter][9] + if (is_poison) { color = "#556815"; stemColor = "black";} //placeholder effect context.fillStyle = color; if(themeName != "Classic"){ if(surface == "rainbow") { @@ -2946,7 +2947,7 @@ function getTintedColor(color, v) { context.moveTo(startC,startR); context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); - context.fillStyle = themes[themeCounter][9]; + context.fillStyle = stemColor; context.fill(); } else drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); From eac93296838866d17a9d7ed61971f6019e35af48 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 19 Feb 2020 16:39:19 -0500 Subject: [PATCH 286/577] Update Framework.html --- Framework.html | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index 34b33a4c..cdad0916 100644 --- a/Framework.html +++ b/Framework.html @@ -40,7 +40,7 @@ Experimental Elements Removeables - + Scissor Lifts @@ -50,6 +50,11 @@ Platforms + + + Liquids + + From 4154edb3305bac982c731d363e47fb5711955f11 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 19 Feb 2020 16:51:07 -0500 Subject: [PATCH 287/577] Update Framework.html --- Framework.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index cdad0916..d5949455 100644 --- a/Framework.html +++ b/Framework.html @@ -40,7 +40,8 @@ Experimental Elements Removeables - + + Scissor Lifts From 70f35679f35f32b1fa2ef3fb6f4306257a87c5de Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 19 Feb 2020 17:12:54 -0500 Subject: [PATCH 288/577] Update SolutionVerification.js --- SolutionVerification.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/SolutionVerification.js b/SolutionVerification.js index 3c3feed8..847deb92 100644 --- a/SolutionVerification.js +++ b/SolutionVerification.js @@ -1162,8 +1162,9 @@ function redo(undoStuff) { undoStuffChanged(undoStuff); } function redoAll(undoStuff) { + //blockSupportRenderCache = []; //didn't work cs = true; - if (undoStuff.redoStack.length === 0) return; // already at the beginning + if (undoStuff.redoStack.length === 0) render(); // already at the beginning animationQueue = []; animationQueueCursor = 0; paradoxes = []; @@ -2305,7 +2306,7 @@ function render() { context.shadowOffsetY = 5; context.shadowColor = "rgba(0,0,0,0.5)"; context.shadowBlur = 4; - var textString = "X"; + var textString = "\u2716"; var textWidth = context.measureText(textString).width; context.fillText(textString, (canvas.width/2) - (textWidth/2), canvas.height/2); } From 4f48d5348bfbfe1653babf7599b18b59e24f2f4e Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 23 Feb 2020 16:11:19 -0500 Subject: [PATCH 289/577] Update Main.js --- Main.js | 7046 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 3531 insertions(+), 3515 deletions(-) diff --git a/Main.js b/Main.js index c59f9fb9..c6958198 100644 --- a/Main.js +++ b/Main.js @@ -1,7 +1,7 @@ function unreachable() { return new Error("unreachable"); } if (typeof VERSION !== "undefined") { - document.getElementById("versionSpan").innerHTML = - '' + VERSION.tag + ''; + document.getElementById("versionSpan").innerHTML = + '' + VERSION.tag + ''; } /*$(document).ready(function() { var fruits1 = getObjectsOfType(FRUIT); @@ -51,30 +51,30 @@ var cs = false; var tileSize = 34; var level; -var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; -var uneditStuff = {undoStack:[], redoStack:[], spanId:"editsSpan", undoButtonId:"uneditButton", redoButtonId:"reeditButton"}; +var unmoveStuff = { undoStack: [], redoStack: [], spanId: "movesSpan", undoButtonId: "unmoveButton", redoButtonId: "removeButton" }; +var uneditStuff = { undoStack: [], redoStack: [], spanId: "editsSpan", undoButtonId: "uneditButton", redoButtonId: "reeditButton" }; var paradoxes = []; function loadLevel(newLevel) { - level = newLevel; - currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); - - activateAnySnakePlease(); - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - undoStuffChanged(unmoveStuff); - uneditStuff.undoStack = []; - uneditStuff.redoStack = []; - undoStuffChanged(uneditStuff); - blockSupportRenderCache = {}; - render(); + level = newLevel; + currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); + + activateAnySnakePlease(); + unmoveStuff.undoStack = []; + unmoveStuff.redoStack = []; + undoStuffChanged(unmoveStuff); + uneditStuff.undoStack = []; + uneditStuff.redoStack = []; + undoStuffChanged(uneditStuff); + blockSupportRenderCache = {}; + render(); } var magicNumber_v0 = "3tFRIoTU"; -var magicNumber = "HyRr4JK1"; +var magicNumber = "HyRr4JK1"; var exampleLevel = magicNumber_v0 + "&" + - "17&31" + - "?" + + "17&31" + + "?" + "0000000000000000000000000000000" + "0000000000000000000000000000000" + "0000000000000000000000000000000" + @@ -92,591 +92,591 @@ var exampleLevel = magicNumber_v0 + "&" + "0000011111111101111111111100000" + "0000001111111100111111111100000" + "0000001111111000111111111100000" + - "/" + - "s0 ?351&350&349/" + - "f0 ?328/" + - "f1 ?366/"; + "/" + + "s0 ?351&350&349/" + + "f0 ?328/" + + "f1 ?366/"; var testLevel_v0 = "3tFRIoTU&5&5?0005*00300024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/"; var testLevel_v0_converted = "HyRr4JK1&5&5?0005*4024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/f0?8/"; function parseLevel(string) { - // magic number - var cursor = 0; - skipWhitespace(); - var versionTag = string.substr(cursor, magicNumber.length); - switch (versionTag) { - case magicNumber_v0: - case magicNumber: break; - default: throw new Error("not a snakefall level"); - } - cursor += magicNumber.length; - consumeKeyword("&"); - - var level = { - height: -1, - width: -1, - map: [], - objects: [], - }; - - // height, width - level.height = readInt(); - consumeKeyword("&"); - level.width = readInt(); - - // map - var mapData = readRun(); - mapData = decompressSerialization(mapData); - if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); - var upconvertedObjects = []; - var fruitCount = 0; - var tileCounter = 0; - for (var i = 0; i < mapData.length; i++) { - var tileCode = mapData[i].charCodeAt(0); - if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { - // fruit used to be a tile code. now it's an object. - upconvertedObjects.push({ - type: FRUIT, - id: fruitCount++, - dead: false, // unused - locations: [i], - }); - tileCode = SPACE; + // magic number + var cursor = 0; + skipWhitespace(); + var versionTag = string.substr(cursor, magicNumber.length); + switch (versionTag) { + case magicNumber_v0: + case magicNumber: break; + default: throw new Error("not a snakefall level"); } - if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; - if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); - level.map.push(tileCode); - } - - // objects - skipWhitespace(); - while (cursor < string.length) { - var object = { - type: "?", - id: -1, - dead: false, - locations: [], + cursor += magicNumber.length; + consumeKeyword("&"); + + var level = { + height: -1, + width: -1, + map: [], + objects: [], }; - // type - object.type = string[cursor]; - var locationsLimit; - if (object.type === SNAKE) locationsLimit = -1; - else if (object.type === BLOCK) locationsLimit = -1; - else if (object.type === FRUIT || object.type === POISON_FRUIT) locationsLimit = 1; - else throw parserError("expected object type code"); - cursor += 1; - - // id - object.id = readInt(); - - // locations - var locationsData = readRun(); - var locationStrings = locationsData.split("&"); - if (locationStrings.length === 0) throw parserError("locations must be non-empty"); - if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); - - locationStrings.forEach(function(locationString) { - var location = parseInt(locationString); - if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); - object.locations.push(location); - }); + // height, width + level.height = readInt(); + consumeKeyword("&"); + level.width = readInt(); + + // map + var mapData = readRun(); + mapData = decompressSerialization(mapData); + if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); + var upconvertedObjects = []; + var fruitCount = 0; + var tileCounter = 0; + for (var i = 0; i < mapData.length; i++) { + var tileCode = mapData[i].charCodeAt(0); + if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { + // fruit used to be a tile code. now it's an object. + upconvertedObjects.push({ + type: FRUIT, + id: fruitCount++, + dead: false, // unused + locations: [i], + }); + tileCode = SPACE; + } + if (tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; + if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); + level.map.push(tileCode); + } - level.objects.push(object); + // objects skipWhitespace(); - } - - if(tileCounter>0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL
    contains experimental elements"; + while (cursor < string.length) { + var object = { + type: "?", + id: -1, + dead: false, + locations: [], + }; + + // type + object.type = string[cursor]; + var locationsLimit; + if (object.type === SNAKE) locationsLimit = -1; + else if (object.type === BLOCK) locationsLimit = -1; + else if (object.type === FRUIT || object.type === POISON_FRUIT) locationsLimit = 1; + else throw parserError("expected object type code"); + cursor += 1; + + // id + object.id = readInt(); + + // locations + var locationsData = readRun(); + var locationStrings = locationsData.split("&"); + if (locationStrings.length === 0) throw parserError("locations must be non-empty"); + if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); + + locationStrings.forEach(function (locationString) { + var location = parseInt(locationString); + if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); + object.locations.push(location); + }); + + level.objects.push(object); + skipWhitespace(); + } + + if (tileCounter > 0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL
    contains experimental elements"; else document.getElementById("levelType").innerHTML = "STANDARD LEVEL
    does not contain experimental elements"; - - for (var i = 0; i < upconvertedObjects.length; i++) { - level.objects.push(upconvertedObjects[i]); - } - return level; + for (var i = 0; i < upconvertedObjects.length; i++) { + level.objects.push(upconvertedObjects[i]); + } + + return level; - function skipWhitespace() { - while (" \n\t\r".indexOf(string[cursor]) !== -1) { - cursor += 1; + function skipWhitespace() { + while (" \n\t\r".indexOf(string[cursor]) !== -1) { + cursor += 1; + } } - } - function consumeKeyword(keyword) { - skipWhitespace(); - if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); - cursor += 1; - } - function readInt() { - skipWhitespace(); - for (var i = cursor; i < string.length; i++) { - if ("0123456789".indexOf(string[i]) === -1) break; + function consumeKeyword(keyword) { + skipWhitespace(); + if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); + cursor += 1; + } + function readInt() { + skipWhitespace(); + for (var i = cursor; i < string.length; i++) { + if ("0123456789".indexOf(string[i]) === -1) break; + } + var substring = string.substring(cursor, i); + if (substring.length === 0) throw parserError("expected int"); + cursor = i; + return parseInt(substring, 10); + } + function readRun() { + consumeKeyword("?"); + var endIndex = string.indexOf("/", cursor); + var substring = string.substring(cursor, endIndex); + cursor = endIndex + 1; + return substring; + } + function parserError(message) { + return new Error("parse error at position " + cursor + ": " + message); } - var substring = string.substring(cursor, i); - if (substring.length === 0) throw parserError("expected int"); - cursor = i; - return parseInt(substring, 10); - } - function readRun() { - consumeKeyword("?"); - var endIndex = string.indexOf("/", cursor); - var substring = string.substring(cursor, endIndex); - cursor = endIndex + 1; - return substring; - } - function parserError(message) { - return new Error("parse error at position " + cursor + ": " + message); - } } function serializeTileCode(tileCode) { - return String.fromCharCode(tileCode); + return String.fromCharCode(tileCode); } function stringifyLevel(level) { - var output = magicNumber + "&"; - output += level.height + "&" + level.width + "\n"; + var output = magicNumber + "&"; + output += level.height + "&" + level.width + "\n"; - output += "?\n"; - for (var r = 0; r < level.height; r++) { - output += " " + level.map.slice(r * level.width, (r + 1) * level.width).map(serializeTileCode).join("") + "\n"; - } - output += "/\n"; + output += "?\n"; + for (var r = 0; r < level.height; r++) { + output += " " + level.map.slice(r * level.width, (r + 1) * level.width).map(serializeTileCode).join("") + "\n"; + } + output += "/\n"; - output += serializeObjects(level.objects); + output += serializeObjects(level.objects); - // sanity check - var shouldBeTheSame = parseLevel(output); - if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken + // sanity check + var shouldBeTheSame = parseLevel(output); + if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken - return output; + return output; } function serializeObjects(objects) { - var output = ""; - for (var i = 0; i < objects.length; i++) { - var object = objects[i]; - output += object.type + object.id + " "; - output += "?" + object.locations.join("&") + "/\n"; - } - return output; + var output = ""; + for (var i = 0; i < objects.length; i++) { + var object = objects[i]; + output += object.type + object.id + " "; + output += "?" + object.locations.join("&") + "/\n"; + } + return output; } function serializeObjectState(object) { - if (object == null) return [0,[]]; - return [object.dead, copyArray(object.locations)]; + if (object == null) return [0, []]; + return [object.dead, copyArray(object.locations)]; } var base66 = "----0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; function compressSerialization(string) { - string = string.replace(/\s+/g, ""); - // run-length encode several 0's in a row, etc. - // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) - var result = ""; - var runStart = 0; - for (var i = 1; i < string.length + 1; i++) { - var runLength = i - runStart; - if (string[i] === string[runStart] && runLength < base66.length - 1) continue; - // end of run - if (runLength >= 4) { - // compress - result += "*" + base66[runLength] + string[runStart]; - } else { - // literal - result += string.substring(runStart, i); + string = string.replace(/\s+/g, ""); + // run-length encode several 0's in a row, etc. + // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) + var result = ""; + var runStart = 0; + for (var i = 1; i < string.length + 1; i++) { + var runLength = i - runStart; + if (string[i] === string[runStart] && runLength < base66.length - 1) continue; + // end of run + if (runLength >= 4) { + // compress + result += "*" + base66[runLength] + string[runStart]; + } else { + // literal + result += string.substring(runStart, i); + } + runStart = i; } - runStart = i; - } - return result; + return result; } function decompressSerialization(string) { - string = string.replace(/\s+/g, ""); - var result = ""; - for (var i = 0; i < string.length; i++) { - if (string[i] === "*") { - i += 1; - var runLength = base66.indexOf(string[i]); - i += 1; - var char = string[i]; - for (var j = 0; j < runLength; j++) { - result += char; - } - } else { - result += string[i]; + string = string.replace(/\s+/g, ""); + var result = ""; + for (var i = 0; i < string.length; i++) { + if (string[i] === "*") { + i += 1; + var runLength = base66.indexOf(string[i]); + i += 1; + var char = string[i]; + for (var j = 0; j < runLength; j++) { + result += char; + } + } else { + result += string[i]; + } } - } - return result; + return result; } var replayMagicNumber = "nmGTi8PB"; function stringifyReplay() { - var output = replayMagicNumber + "&"; - // only specify the snake id in an input if it's different from the previous. - // the first snake index is 0 to optimize for the single-snake case. - var currentSnakeId = 0; - for (var i = 0; i < unmoveStuff.undoStack.length; i++) { - var firstChange = unmoveStuff.undoStack[i][0]; - if (firstChange[0] !== "i") throw unreachable(); - var snakeId = firstChange[1]; - var dr = firstChange[2]; - var dc = firstChange[3]; - var directionCode; - if (dr ===-1 && dc === 0) directionCode = "u"; - else if (dr === 0 && dc ===-1) directionCode = "l"; - else if (dr === 1 && dc === 0) directionCode = "d"; - else if (dr === 0 && dc === 1) directionCode = "r"; - else throw unreachable(); - if (snakeId !== currentSnakeId) { - output += snakeId; // int to string - currentSnakeId = snakeId; + var output = replayMagicNumber + "&"; + // only specify the snake id in an input if it's different from the previous. + // the first snake index is 0 to optimize for the single-snake case. + var currentSnakeId = 0; + for (var i = 0; i < unmoveStuff.undoStack.length; i++) { + var firstChange = unmoveStuff.undoStack[i][0]; + if (firstChange[0] !== "i") throw unreachable(); + var snakeId = firstChange[1]; + var dr = firstChange[2]; + var dc = firstChange[3]; + var directionCode; + if (dr === -1 && dc === 0) directionCode = "u"; + else if (dr === 0 && dc === -1) directionCode = "l"; + else if (dr === 1 && dc === 0) directionCode = "d"; + else if (dr === 0 && dc === 1) directionCode = "r"; + else throw unreachable(); + if (snakeId !== currentSnakeId) { + output += snakeId; // int to string + currentSnakeId = snakeId; + } + output += directionCode; } - output += directionCode; - } - return output; + return output; } function parseAndLoadReplay(string) { - string = decompressSerialization(string); - var expectedPrefix = replayMagicNumber + "&"; - if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); - var cursor = expectedPrefix.length; - - // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. - activeSnakeId = 0; - while (cursor < string.length) { - var snakeIdStr = ""; - var c = string.charAt(cursor); - cursor += 1; - while ('0' <= c && c <= '9') { - snakeIdStr += c; - if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); - c = string.charAt(cursor); - cursor += 1; - } - if (snakeIdStr.length > 0) { - activeSnakeId = parseInt(snakeIdStr); - // don't just validate when switching snakes, but on every move. - } + string = decompressSerialization(string); + var expectedPrefix = replayMagicNumber + "&"; + if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); + var cursor = expectedPrefix.length; + + // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. + activeSnakeId = 0; + while (cursor < string.length) { + var snakeIdStr = ""; + var c = string.charAt(cursor); + cursor += 1; + while ('0' <= c && c <= '9') { + snakeIdStr += c; + if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); + c = string.charAt(cursor); + cursor += 1; + } + if (snakeIdStr.length > 0) { + activeSnakeId = parseInt(snakeIdStr); + // don't just validate when switching snakes, but on every move. + } - // doing a move. - if (!getSnakes().some(function(snake) { - return snake.id === activeSnakeId; - })) { - throw new Error("invalid snake id: " + activeSnakeId); - } - switch (c) { - case 'l': move( 0, -1); break; - case 'u': move(-1, 0); break; - case 'r': move( 0, 1); break; - case 'd': move( 1, 0); break; - default: throw new Error("replay string has invalid direction: " + c); + // doing a move. + if (!getSnakes().some(function (snake) { + return snake.id === activeSnakeId; + })) { + throw new Error("invalid snake id: " + activeSnakeId); + } + switch (c) { + case 'l': move(0, -1); break; + case 'u': move(-1, 0); break; + case 'r': move(0, 1); break; + case 'd': move(1, 0); break; + default: throw new Error("replay string has invalid direction: " + c); + } } - } - // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. - reset(unmoveStuff); - document.getElementById("removeButton").classList.add("click-me"); + // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. + reset(unmoveStuff); + document.getElementById("removeButton").classList.add("click-me"); } var currentSerializedLevel; function saveLevel() { - if (isDead()) return alert("Can't save while you're dead!"); - var serializedLevel = compressSerialization(stringifyLevel(level)); - currentSerializedLevel = serializedLevel; - var hash = "#level=" + serializedLevel; - expectHash = hash; - location.hash = hash; - - // This marks a starting point for solving the level. - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - editorHasBeenTouched = false; - undoStuffChanged(unmoveStuff); + if (isDead()) return alert("Can't save while you're dead!"); + var serializedLevel = compressSerialization(stringifyLevel(level)); + currentSerializedLevel = serializedLevel; + var hash = "#level=" + serializedLevel; + expectHash = hash; + location.hash = hash; + + // This marks a starting point for solving the level. + unmoveStuff.undoStack = []; + unmoveStuff.redoStack = []; + editorHasBeenTouched = false; + undoStuffChanged(unmoveStuff); } function saveReplay() { - if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); - // preserve the level in the url bar. - var hash = "#level=" + currentSerializedLevel; - if (dirtyState === REPLAY_DIRTY) { - // there is a replay to save - hash += "#replay=" + compressSerialization(stringifyReplay()); - } - expectHash = hash; - location.hash = hash; + if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); + // preserve the level in the url bar. + var hash = "#level=" + currentSerializedLevel; + if (dirtyState === REPLAY_DIRTY) { + // there is a replay to save + hash += "#replay=" + compressSerialization(stringifyReplay()); + } + expectHash = hash; + location.hash = hash; } function deepEquals(a, b) { - if (a == null) return b == null; - if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; - if (Array.isArray(a)) { - if (!Array.isArray(b)) return false; - if (a.length !== b.length) return false; - for (var i = 0; i < a.length; i++) { - if (!deepEquals(a[i], b[i])) return false; + if (a == null) return b == null; + if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; + if (Array.isArray(a)) { + if (!Array.isArray(b)) return false; + if (a.length !== b.length) return false; + for (var i = 0; i < a.length; i++) { + if (!deepEquals(a[i], b[i])) return false; + } + return true; + } + // must be objects + var aKeys = Object.keys(a); + var bKeys = Object.keys(b); + if (aKeys.length !== bKeys.length) return false; + aKeys.sort(); + bKeys.sort(); + if (!deepEquals(aKeys, bKeys)) return false; + for (var i = 0; i < aKeys.length; i++) { + if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; } return true; - } - // must be objects - var aKeys = Object.keys(a); - var bKeys = Object.keys(b); - if (aKeys.length !== bKeys.length) return false; - aKeys.sort(); - bKeys.sort(); - if (!deepEquals(aKeys, bKeys)) return false; - for (var i = 0; i < aKeys.length; i++) { - if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; - } - return true; } function getLocation(level, r, c) { - if (!isInBounds(level, r, c)) throw unreachable(); - return r * level.width + c; + if (!isInBounds(level, r, c)) throw unreachable(); + return r * level.width + c; } function getRowcol(level, location) { - if (location < 0 || location >= level.width * level.height) throw unreachable(); - var r = Math.floor(location / level.width); - var c = location % level.width; - return {r:r, c:c}; + if (location < 0 || location >= level.width * level.height) throw unreachable(); + var r = Math.floor(location / level.width); + var c = location % level.width; + return { r: r, c: c }; } function isInBounds(level, r, c) { - if (c < 0 || c >= level.width) return false;; - if (r < 0 || r >= level.height) return false;; - return true; + if (c < 0 || c >= level.width) return false;; + if (r < 0 || r >= level.height) return false;; + return true; } function offsetLocation(location, dr, dc) { - var rowcol = getRowcol(level, location); - return getLocation(level, rowcol.r + dr, rowcol.c + dc); + var rowcol = getRowcol(level, location); + return getLocation(level, rowcol.r + dr, rowcol.c + dc); } var SHIFT = 1; var CTRL = 2; var ALT = 4; -document.addEventListener("keydown", function(event) { - var modifierMask = ( - (event.shiftKey ? SHIFT : 0) | - (event.ctrlKey ? CTRL : 0) | - (event.altKey ? ALT : 0) - ); - switch (event.keyCode) { - case 37: // left - if (modifierMask === 0) { move(0, -1); break; } - return; - case 38: // up - if (modifierMask === 0) { move(-1, 0); break; } - return; - case 39: // right - if (modifierMask === 0) { move(0, 1); break; } - return; - case 40: // down - if (modifierMask === 0) { move(1, 0); break; } - return; - case 8: // backspace - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Q".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Z".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { undo(uneditStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL|SHIFT) { redo(uneditStuff); break; } - return; - case "Y".charCodeAt(0): - if (modifierMask === 0) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { redo(uneditStuff); break; } - return; - case "R".charCodeAt(0): - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } - if (modifierMask === 0) { reset(unmoveStuff); break; } - if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLR); break; } - return; - case 220: // backslash - if (modifierMask === 0) { toggleShowEditor(); break; } - return; - case "A".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, -1); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PORTAL); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { selectAll(); break; } - return; - case "E".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(EXIT); break; } - return; - case 46: // delete - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - return; - case "W".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(WOODPLATFORM); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(WATER); break; } - return; - case "S".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPIKE); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(SNAKE); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { saveLevel(); break; } - if (!persistentState.showEditor && modifierMask === CTRL) { saveReplay(); break; } - if (modifierMask === (CTRL|SHIFT)) { saveReplay(); break; } - return; - case "X".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } - return; - case "F".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(POISON_FRUIT); break; } - return; - case "D".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLD); break; } - return; - case "B".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(BUBBLE); break; } - return; - case "P".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } - return; - case "U".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLU); break; } - return; - case "L".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOSEDLIFT); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(OPENLIFT); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLL); break; } - return; - case "G".charCodeAt(0): - if (modifierMask === 0) { toggleGrid(); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } - return; - case "C".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { toggleCollision(); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } - return; - case "V".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(LAVA); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } - case "T".charCodeAt(0): - toggleTheme(); break; - return; - case 32: // spacebar - case 9: // tab - if (modifierMask === 0) { switchSnakes( 1); break; } - if (modifierMask === SHIFT) { switchSnakes(-1); break; } - return; - case "1".charCodeAt(0): - case "2".charCodeAt(0): - case "3".charCodeAt(0): - case "4".charCodeAt(0): - var index = event.keyCode - "1".charCodeAt(0); - var delta; - if (modifierMask === 0) { - delta = 1; - } else if (modifierMask === SHIFT) { - delta = -1; - } else return; - if (isAlive()) { - (function() { - var snakes = findSnakesOfColor(index); - if (snakes.length === 0) return; - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; +document.addEventListener("keydown", function (event) { + var modifierMask = ( + (event.shiftKey ? SHIFT : 0) | + (event.ctrlKey ? CTRL : 0) | + (event.altKey ? ALT : 0) + ); + switch (event.keyCode) { + case 37: // left + if (modifierMask === 0) { move(0, -1); break; } + return; + case 38: // up + if (modifierMask === 0) { move(-1, 0); break; } + return; + case 39: // right + if (modifierMask === 0) { move(0, 1); break; } + return; + case 40: // down + if (modifierMask === 0) { move(1, 0); break; } + return; + case 8: // backspace + if (modifierMask === 0) { undo(unmoveStuff); break; } + if (modifierMask === SHIFT) { redo(unmoveStuff); break; } + return; + case "Q".charCodeAt(0): + if (modifierMask === 0) { undo(unmoveStuff); break; } + if (modifierMask === SHIFT) { redo(unmoveStuff); break; } + return; + case "Z".charCodeAt(0): + if (modifierMask === 0) { undo(unmoveStuff); break; } + if (modifierMask === SHIFT) { redo(unmoveStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL) { undo(uneditStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL | SHIFT) { redo(uneditStuff); break; } + return; + case "Y".charCodeAt(0): + if (modifierMask === 0) { redo(unmoveStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL) { redo(uneditStuff); break; } + return; + case "R".charCodeAt(0): + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } + if (modifierMask === 0) { reset(unmoveStuff); break; } + if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLR); break; } + return; + case 220: // backslash + if (modifierMask === 0) { toggleShowEditor(); break; } + return; + case "A".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(0, -1); break; } + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PORTAL); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } + if (persistentState.showEditor && modifierMask === CTRL) { selectAll(); break; } + return; + case "E".charCodeAt(0): + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(EXIT); break; } + return; + case 46: // delete + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } + return; + case "W".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(WOODPLATFORM); break; } + if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(WATER); break; } + return; + case "S".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPIKE); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(SNAKE); break; } + if (persistentState.showEditor && modifierMask === CTRL) { saveLevel(); break; } + if (!persistentState.showEditor && modifierMask === CTRL) { saveReplay(); break; } + if (modifierMask === (CTRL | SHIFT)) { saveReplay(); break; } + return; + case "X".charCodeAt(0): + if (persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } + return; + case "F".charCodeAt(0): + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(POISON_FRUIT); break; } + return; + case "D".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } + if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLD); break; } + return; + case "B".charCodeAt(0): + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(BUBBLE); break; } + return; + case "P".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } + return; + case "U".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLU); break; } + return; + case "L".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOSEDLIFT); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(OPENLIFT); break; } + if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLL); break; } + return; + case "G".charCodeAt(0): + if (modifierMask === 0) { toggleGrid(); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } + return; + case "C".charCodeAt(0): + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { toggleCollision(); break; } + if (persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } + return; + case "V".charCodeAt(0): + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(LAVA); break; } + if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } + case "T".charCodeAt(0): + toggleTheme(); break; + return; + case 32: // spacebar + case 9: // tab + if (modifierMask === 0) { switchSnakes(1); break; } + if (modifierMask === SHIFT) { switchSnakes(-1); break; } + return; + case "1".charCodeAt(0): + case "2".charCodeAt(0): + case "3".charCodeAt(0): + case "4".charCodeAt(0): + var index = event.keyCode - "1".charCodeAt(0); + var delta; + if (modifierMask === 0) { + delta = 1; + } else if (modifierMask === SHIFT) { + delta = -1; + } else return; + if (isAlive()) { + (function () { + var snakes = findSnakesOfColor(index); + if (snakes.length === 0) return; + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) { + activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; + return; + } + } + activeSnakeId = snakes[0].id; + })(); } - } - activeSnakeId = snakes[0].id; - })(); - } - break; - case 27: // escape - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(null); break; } - return; - default: return; - } - event.preventDefault(); - render(); + break; + case 27: // escape + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(null); break; } + return; + default: return; + } + event.preventDefault(); + render(); }); -document.getElementById("switchSnakesButton").addEventListener("click", function() { - switchSnakes(1); - render(); +document.getElementById("switchSnakesButton").addEventListener("click", function () { + switchSnakes(1); + render(); }); function switchSnakes(delta) { - if (!isAlive()) return; - var snakes = getSnakes(); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; + if (!isAlive()) return; + var snakes = getSnakes(); + snakes.sort(compareId); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) { + activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; + return; + } } - } - activeSnakeId = snakes[0].id; + activeSnakeId = snakes[0].id; } -document.getElementById("showGridButton").addEventListener("click", function() { - toggleGrid(); +document.getElementById("showGridButton").addEventListener("click", function () { + toggleGrid(); }); -document.getElementById("saveProgressButton").addEventListener("click", function() { - saveReplay(); +document.getElementById("saveProgressButton").addEventListener("click", function () { + saveReplay(); }); -document.getElementById("checkSolutionButton").addEventListener("click", function() { - redoAll(unmoveStuff); +document.getElementById("checkSolutionButton").addEventListener("click", function () { + redoAll(unmoveStuff); }); -document.getElementById("restartButton").addEventListener("click", function() { - reset(unmoveStuff); - render(); +document.getElementById("restartButton").addEventListener("click", function () { + reset(unmoveStuff); + render(); }); -document.getElementById("unmoveButton").addEventListener("click", function() { - undo(unmoveStuff); - render(); +document.getElementById("unmoveButton").addEventListener("click", function () { + undo(unmoveStuff); + render(); }); -document.getElementById("removeButton").addEventListener("click", function() { - redo(unmoveStuff); - render(); +document.getElementById("removeButton").addEventListener("click", function () { + redo(unmoveStuff); + render(); }); -document.getElementById("showHideEditor").addEventListener("click", function() { - toggleShowEditor(); +document.getElementById("showHideEditor").addEventListener("click", function () { + toggleShowEditor(); }); function toggleShowEditor() { - persistentState.showEditor = !persistentState.showEditor; - savePersistentState(); - showEditorChanged(); + persistentState.showEditor = !persistentState.showEditor; + savePersistentState(); + showEditorChanged(); } function toggleGrid() { - persistentState.showGrid = !persistentState.showGrid; - savePersistentState(); - render(); + persistentState.showGrid = !persistentState.showGrid; + savePersistentState(); + render(); } -["serializationTextarea", "shareLinkTextbox"].forEach(function(id) { - document.getElementById(id).addEventListener("keydown", function(event) { - // let things work normally - event.stopPropagation(); - }); +["serializationTextarea", "shareLinkTextbox"].forEach(function (id) { + document.getElementById(id).addEventListener("keydown", function (event) { + // let things work normally + event.stopPropagation(); + }); }); -document.getElementById("submitSerializationButton").addEventListener("click", function() { - var string = document.getElementById("serializationTextarea").value; - try { - var newLevel = parseLevel(string); - } catch (e) { - alert(e); - return; - } - loadLevel(newLevel); +document.getElementById("submitSerializationButton").addEventListener("click", function () { + var string = document.getElementById("serializationTextarea").value; + try { + var newLevel = parseLevel(string); + } catch (e) { + alert(e); + return; + } + loadLevel(newLevel); }); -document.getElementById("shareLinkTextbox").addEventListener("focus", function() { - setTimeout(function() { - document.getElementById("shareLinkTextbox").select(); - }, 0); +document.getElementById("shareLinkTextbox").addEventListener("focus", function () { + setTimeout(function () { + document.getElementById("shareLinkTextbox").select(); + }, 0); }); var paintBrushTileCode = null; @@ -689,765 +689,765 @@ var resizeDragAnchorRowcol = null; var clipboardData = null; var clipboardOffsetRowcol = null; var paintButtonIdAndTileCodes = [ - ["resizeButton", "resize"], - ["selectButton", "select"], - ["pasteButton", "paste"], - ["paintSpaceButton", SPACE], - ["paintWallButton", WALL], - ["paintSpikeButton", SPIKE], - ["paintExitButton", EXIT], - ["paintFruitButton", FRUIT], - ["paintPoisonFruitButton", POISON_FRUIT], - ["paintPortalButton", PORTAL], - ["paintPlatformButton", PLATFORM], - ["paintWoodPlatformButton", WOODPLATFORM], - ["paintOneWayWallUButton", ONEWAYWALLU], - ["paintOneWayWallDButton", ONEWAYWALLD], - ["paintOneWayWallLButton", ONEWAYWALLL], - ["paintOneWayWallRButton", ONEWAYWALLR], - ["paintClosedLiftButton", CLOSEDLIFT], - ["paintOpenLiftButton", OPENLIFT], - ["paintCloudButton", CLOUD], - ["paintBubbleButton", BUBBLE], - ["paintLavaButton", LAVA], - ["paintWaterButton", WATER], - ["paintSnakeButton", SNAKE], - ["paintBlockButton", BLOCK], + ["resizeButton", "resize"], + ["selectButton", "select"], + ["pasteButton", "paste"], + ["paintSpaceButton", SPACE], + ["paintWallButton", WALL], + ["paintSpikeButton", SPIKE], + ["paintExitButton", EXIT], + ["paintFruitButton", FRUIT], + ["paintPoisonFruitButton", POISON_FRUIT], + ["paintPortalButton", PORTAL], + ["paintPlatformButton", PLATFORM], + ["paintWoodPlatformButton", WOODPLATFORM], + ["paintOneWayWallUButton", ONEWAYWALLU], + ["paintOneWayWallDButton", ONEWAYWALLD], + ["paintOneWayWallLButton", ONEWAYWALLL], + ["paintOneWayWallRButton", ONEWAYWALLR], + ["paintClosedLiftButton", CLOSEDLIFT], + ["paintOpenLiftButton", OPENLIFT], + ["paintCloudButton", CLOUD], + ["paintBubbleButton", BUBBLE], + ["paintLavaButton", LAVA], + ["paintWaterButton", WATER], + ["paintSnakeButton", SNAKE], + ["paintBlockButton", BLOCK], ]; -paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - document.getElementById(id).addEventListener("click", function() { - setPaintBrushTileCode(tileCode); - }); +paintButtonIdAndTileCodes.forEach(function (pair) { + var id = pair[0]; + var tileCode = pair[1]; + document.getElementById(id).addEventListener("click", function () { + setPaintBrushTileCode(tileCode); + }); }); -document.getElementById("uneditButton").addEventListener("click", function() { - undo(uneditStuff); - render(); +document.getElementById("uneditButton").addEventListener("click", function () { + undo(uneditStuff); + render(); }); -document.getElementById("reeditButton").addEventListener("click", function() { - redo(uneditStuff); - render(); +document.getElementById("reeditButton").addEventListener("click", function () { + redo(uneditStuff); + render(); }); -document.getElementById("saveLevelButton").addEventListener("click", function() { - saveLevel(); +document.getElementById("saveLevelButton").addEventListener("click", function () { + saveLevel(); }); -document.getElementById("copyButton").addEventListener("click", function() { - copySelection(); +document.getElementById("copyButton").addEventListener("click", function () { + copySelection(); }); -document.getElementById("cutButton").addEventListener("click", function() { - cutSelection(); +document.getElementById("cutButton").addEventListener("click", function () { + cutSelection(); }); -document.getElementById("cheatGravityButton").addEventListener("click", function() { - toggleGravity(); +document.getElementById("cheatGravityButton").addEventListener("click", function () { + toggleGravity(); }); -document.getElementById("cheatCollisionButton").addEventListener("click", function() { - toggleCollision(); +document.getElementById("cheatCollisionButton").addEventListener("click", function () { + toggleCollision(); }); -document.getElementById("themeButton").addEventListener("click", function() { - toggleTheme(); +document.getElementById("themeButton").addEventListener("click", function () { + toggleTheme(); }); function toggleTheme() { - if(themeCounter"; } function toggleGravity() { - isGravityEnabled = !isGravityEnabled; - isCollisionEnabled = true; - refreshCheatButtonText(); + isGravityEnabled = !isGravityEnabled; + isCollisionEnabled = true; + refreshCheatButtonText(); } function toggleCollision() { - isCollisionEnabled = !isCollisionEnabled; - isGravityEnabled = false; - refreshCheatButtonText(); + isCollisionEnabled = !isCollisionEnabled; + isGravityEnabled = false; + refreshCheatButtonText(); } function refreshCheatButtonText() { - document.getElementById("cheatGravityButton").textContent = isGravityEnabled ? "Gravity: ON" : "Gravity: OFF"; - document.getElementById("cheatGravityButton").style.background = isGravityEnabled ? "" : "#f88"; + document.getElementById("cheatGravityButton").textContent = isGravityEnabled ? "Gravity: ON" : "Gravity: OFF"; + document.getElementById("cheatGravityButton").style.background = isGravityEnabled ? "" : "#f88"; - document.getElementById("cheatCollisionButton").textContent = isCollisionEnabled ? "Collision: ON" : "Collision: OFF"; - document.getElementById("cheatCollisionButton").style.background = isCollisionEnabled ? "" : "#f88"; + document.getElementById("cheatCollisionButton").textContent = isCollisionEnabled ? "Collision: ON" : "Collision: OFF"; + document.getElementById("cheatCollisionButton").style.background = isCollisionEnabled ? "" : "#f88"; } // be careful with location vs rowcol, because this variable is used when resizing var lastDraggingRowcol = null; var hoverLocation = null; var draggingChangeLog = null; -canvas.addEventListener("mousedown", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - var location = getLocationFromEvent(event); - if (persistentState.showEditor && paintBrushTileCode != null) { - // editor tool - lastDraggingRowcol = getRowcol(level, location); - if (paintBrushTileCode === "select") selectionStart = location; - if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; - draggingChangeLog = []; - paintAtLocation(location, draggingChangeLog); - } else { - // playtime - var object = findObjectAtLocation(location); - if (object == null) return; - if (object.type !== SNAKE) return; - // active snake - activeSnakeId = object.id; - render(); - } -}); -canvas.addEventListener("dblclick", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - if (persistentState.showEditor && paintBrushTileCode === "select") { - // double click with select tool +canvas.addEventListener("mousedown", function (event) { + if (event.altKey) return; + if (event.button !== 0) return; + event.preventDefault(); var location = getLocationFromEvent(event); - var object = findObjectAtLocation(location); - if (object == null) return; - stopDragging(); - if (object.type === SNAKE) { - // edit snakes of this color - paintBrushTileCode = SNAKE; - paintBrushSnakeColorIndex = object.id % snakeColors.length; - } else if (object.type === BLOCK) { - // edit this particular block - paintBrushTileCode = BLOCK; - paintBrushBlockId = object.id; - } else if (object.type === FRUIT) { - // edit fruits, i guess - paintBrushTileCode = FRUIT; - } else if (object.type === POISON_FRUIT) { - // edit poison fruits, i guess - paintBrushTileCode = POISON_FRUIT; + if (persistentState.showEditor && paintBrushTileCode != null) { + // editor tool + lastDraggingRowcol = getRowcol(level, location); + if (paintBrushTileCode === "select") selectionStart = location; + if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; + draggingChangeLog = []; + paintAtLocation(location, draggingChangeLog); + } else { + // playtime + var object = findObjectAtLocation(location); + if (object == null) return; + if (object.type !== SNAKE) return; + // active snake + activeSnakeId = object.id; + render(); } - else throw unreachable(); - paintBrushTileCodeChanged(); - } }); -document.addEventListener("mouseup", function(event) { - stopDragging(); +canvas.addEventListener("dblclick", function (event) { + if (event.altKey) return; + if (event.button !== 0) return; + event.preventDefault(); + if (persistentState.showEditor && paintBrushTileCode === "select") { + // double click with select tool + var location = getLocationFromEvent(event); + var object = findObjectAtLocation(location); + if (object == null) return; + stopDragging(); + if (object.type === SNAKE) { + // edit snakes of this color + paintBrushTileCode = SNAKE; + paintBrushSnakeColorIndex = object.id % snakeColors.length; + } else if (object.type === BLOCK) { + // edit this particular block + paintBrushTileCode = BLOCK; + paintBrushBlockId = object.id; + } else if (object.type === FRUIT) { + // edit fruits, i guess + paintBrushTileCode = FRUIT; + } else if (object.type === POISON_FRUIT) { + // edit poison fruits, i guess + paintBrushTileCode = POISON_FRUIT; + } + else throw unreachable(); + paintBrushTileCodeChanged(); + } +}); +document.addEventListener("mouseup", function (event) { + stopDragging(); }); function stopDragging() { - if (lastDraggingRowcol != null) { - // release the draggin' - lastDraggingRowcol = null; - paintBrushObject = null; - resizeDragAnchorRowcol = null; - pushUndo(uneditStuff, draggingChangeLog); - draggingChangeLog = null; - } + if (lastDraggingRowcol != null) { + // release the draggin' + lastDraggingRowcol = null; + paintBrushObject = null; + resizeDragAnchorRowcol = null; + pushUndo(uneditStuff, draggingChangeLog); + draggingChangeLog = null; + } } -canvas.addEventListener("mousemove", function(event) { - if (!persistentState.showEditor) return; - var location = getLocationFromEvent(event); - var mouseRowcol = getRowcol(level, location); - if (lastDraggingRowcol != null) { - // Dragging Force - Through the Fruit and Flames - var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); - // we need to get rowcols for everything before we start dragging, because dragging might resize the world. - var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function(location) { - return getRowcol(level, location); - }); - path.forEach(function(rowcol) { - // convert to location at the last minute in case each of these steps is changing the coordinate system. - paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); - }); - lastDraggingRowcol = mouseRowcol; - hoverLocation = null; - } else { - // hovering - if (hoverLocation !== location) { - hoverLocation = location; - render(); +canvas.addEventListener("mousemove", function (event) { + if (!persistentState.showEditor) return; + var location = getLocationFromEvent(event); + var mouseRowcol = getRowcol(level, location); + if (lastDraggingRowcol != null) { + // Dragging Force - Through the Fruit and Flames + var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); + // we need to get rowcols for everything before we start dragging, because dragging might resize the world. + var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function (location) { + return getRowcol(level, location); + }); + path.forEach(function (rowcol) { + // convert to location at the last minute in case each of these steps is changing the coordinate system. + paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); + }); + lastDraggingRowcol = mouseRowcol; + hoverLocation = null; + } else { + // hovering + if (hoverLocation !== location) { + hoverLocation = location; + render(); + } } - } }); -canvas.addEventListener("mouseout", function() { - if (hoverLocation !== location) { - // turn off the hover when the mouse leaves - hoverLocation = null; - render(); - } +canvas.addEventListener("mouseout", function () { + if (hoverLocation !== location) { + // turn off the hover when the mouse leaves + hoverLocation = null; + render(); + } }); function getLocationFromEvent(event) { - var r = Math.floor(eventToMouseY(event, canvas) / tileSize); - var c = Math.floor(eventToMouseX(event, canvas) / tileSize); - // since the canvas is centered, the bounding client rect can be half-pixel aligned, - // resulting in slightly out-of-bounds mouse events. - r = clamp(r, 0, level.height); - c = clamp(c, 0, level.width); - return getLocation(level, r, c); + var r = Math.floor(eventToMouseY(event, canvas) / tileSize); + var c = Math.floor(eventToMouseX(event, canvas) / tileSize); + // since the canvas is centered, the bounding client rect can be half-pixel aligned, + // resulting in slightly out-of-bounds mouse events. + r = clamp(r, 0, level.height); + c = clamp(c, 0, level.width); + return getLocation(level, r, c); } function eventToMouseX(event, canvas) { return event.clientX - canvas.getBoundingClientRect().left; } function eventToMouseY(event, canvas) { return event.clientY - canvas.getBoundingClientRect().top; } function selectAll() { - selectionStart = 0; - selectionEnd = level.map.length - 1; - setPaintBrushTileCode("select"); + selectionStart = 0; + selectionEnd = level.map.length - 1; + setPaintBrushTileCode("select"); } function setPaintBrushTileCode(tileCode) { - if (tileCode === "paste") { - // make sure we have something to paste - if (clipboardData == null) return; - } - if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { - // usually this means to fill in the selection - if (tileCode == null) { - // cancel selection - selectionStart = null; - selectionEnd = null; - return; + if (tileCode === "paste") { + // make sure we have something to paste + if (clipboardData == null) return; } - // fill in the selection - fillSelection(tileCode); - selectionStart = null; - selectionEnd = null; - return; - } - if (tileCode === SNAKE) { - if (paintBrushTileCode === SNAKE) { - // next snake color - paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; + if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { + // usually this means to fill in the selection + if (tileCode == null) { + // cancel selection + selectionStart = null; + selectionEnd = null; + return; + } + // fill in the selection + fillSelection(tileCode); + selectionStart = null; + selectionEnd = null; + return; } - } else if (tileCode === BLOCK) { - var blocks = getBlocks(); - if (paintBrushTileCode === BLOCK && blocks.length > 0) { - // cycle through block ids - blocks.sort(compareId); - if (paintBrushBlockId != null) { - (function() { - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id === paintBrushBlockId) { - i += 1; - if (i < blocks.length) { - // next block id - paintBrushBlockId = blocks[i].id; - } else { - // new block id - paintBrushBlockId = null; - } - return; + if (tileCode === SNAKE) { + if (paintBrushTileCode === SNAKE) { + // next snake color + paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; + } + } else if (tileCode === BLOCK) { + var blocks = getBlocks(); + if (paintBrushTileCode === BLOCK && blocks.length > 0) { + // cycle through block ids + blocks.sort(compareId); + if (paintBrushBlockId != null) { + (function () { + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].id === paintBrushBlockId) { + i += 1; + if (i < blocks.length) { + // next block id + paintBrushBlockId = blocks[i].id; + } else { + // new block id + paintBrushBlockId = null; + } + return; + } + } + throw unreachable() + })(); + } else { + // first one + paintBrushBlockId = blocks[0].id; } - } - throw unreachable() - })(); - } else { - // first one - paintBrushBlockId = blocks[0].id; - } - } else { - // new block id - paintBrushBlockId = null; - } - } else if (tileCode == null) { - // escape - if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { - // stop editing this block, but keep the block brush selected - tileCode = BLOCK; - paintBrushBlockId = null; + } else { + // new block id + paintBrushBlockId = null; + } + } else if (tileCode == null) { + // escape + if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { + // stop editing this block, but keep the block brush selected + tileCode = BLOCK; + paintBrushBlockId = null; + } } - } - paintBrushTileCode = tileCode; - paintBrushTileCodeChanged(); + paintBrushTileCode = tileCode; + paintBrushTileCodeChanged(); } function paintBrushTileCodeChanged() { - paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - var backgroundStyle = ""; - var textColor = ""; - if (tileCode === paintBrushTileCode) { - if (tileCode === SNAKE) { - // show the color of the active snake in the color of the button - backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; - } else { - backgroundStyle = "linear-gradient(#4b91ff, #055ce4)"; - textColor = "white"; - } - } - document.getElementById(id).style.background = backgroundStyle; - document.getElementById(id).style.color = textColor; - }); + paintButtonIdAndTileCodes.forEach(function (pair) { + var id = pair[0]; + var tileCode = pair[1]; + var backgroundStyle = ""; + var textColor = ""; + if (tileCode === paintBrushTileCode) { + if (tileCode === SNAKE) { + // show the color of the active snake in the color of the button + backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; + } else { + backgroundStyle = "linear-gradient(#4b91ff, #055ce4)"; + textColor = "white"; + } + } + document.getElementById(id).style.background = backgroundStyle; + document.getElementById(id).style.color = textColor; + }); - var isSelectionMode = paintBrushTileCode === "select"; - ["cutButton", "copyButton"].forEach(function (id) { - document.getElementById(id).disabled = !isSelectionMode; - }); - document.getElementById("pasteButton").disabled = clipboardData == null; + var isSelectionMode = paintBrushTileCode === "select"; + ["cutButton", "copyButton"].forEach(function (id) { + document.getElementById(id).disabled = !isSelectionMode; + }); + document.getElementById("pasteButton").disabled = clipboardData == null; - render(); + render(); } function cutSelection() { - copySelection(); - fillSelection(SPACE); - render(); + copySelection(); + fillSelection(SPACE); + render(); } function copySelection() { - var selectedLocations = getSelectedLocations(); - if (selectedLocations.length === 0) return; - var selectedObjects = []; - selectedLocations.forEach(function(location) { - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(selectedObjects, object); - }); - setClipboardData({ - level: JSON.parse(JSON.stringify(level)), - selectedLocations: selectedLocations, - selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), - }); + var selectedLocations = getSelectedLocations(); + if (selectedLocations.length === 0) return; + var selectedObjects = []; + selectedLocations.forEach(function (location) { + var object = findObjectAtLocation(location); + if (object != null) addIfNotPresent(selectedObjects, object); + }); + setClipboardData({ + level: JSON.parse(JSON.stringify(level)), + selectedLocations: selectedLocations, + selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), + }); } function setClipboardData(data) { - // find the center - var minR = Infinity; - var maxR = -Infinity; - var minC = Infinity; - var maxC = -Infinity; - data.selectedLocations.forEach(function(location) { - var rowcol = getRowcol(data.level, location); - if (rowcol.r < minR) minR = rowcol.r; - if (rowcol.r > maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var offsetR = Math.floor((minR + maxR) / 2); - var offsetC = Math.floor((minC + maxC) / 2); - - clipboardData = data; - clipboardOffsetRowcol = {r:offsetR, c:offsetC}; - paintBrushTileCodeChanged(); + // find the center + var minR = Infinity; + var maxR = -Infinity; + var minC = Infinity; + var maxC = -Infinity; + data.selectedLocations.forEach(function (location) { + var rowcol = getRowcol(data.level, location); + if (rowcol.r < minR) minR = rowcol.r; + if (rowcol.r > maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var offsetR = Math.floor((minR + maxR) / 2); + var offsetC = Math.floor((minC + maxC) / 2); + + clipboardData = data; + clipboardOffsetRowcol = { r: offsetR, c: offsetC }; + paintBrushTileCodeChanged(); } function fillSelection(tileCode) { - var changeLog = []; - var locations = getSelectedLocations(); - locations.forEach(function(location) { - if (level.map[location] !== tileCode) { - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; - } - removeAnyObjectAtLocation(location, changeLog); - }); - pushUndo(uneditStuff, changeLog); + var changeLog = []; + var locations = getSelectedLocations(); + locations.forEach(function (location) { + if (level.map[location] !== tileCode) { + changeLog.push(["m", location, level.map[location], tileCode]); + level.map[location] = tileCode; + } + removeAnyObjectAtLocation(location, changeLog); + }); + pushUndo(uneditStuff, changeLog); } function getSelectedLocations() { - if (selectionStart == null || selectionEnd == null) return []; - var rowcol1 = getRowcol(level, selectionStart); - var rowcol2 = getRowcol(level, selectionEnd); - var r1 = rowcol1.r; - var c1 = rowcol1.c; - var r2 = rowcol2.r; - var c2 = rowcol2.c; - if (r2 < r1) { - var tmp = r1; - r1 = r2; - r2 = tmp; - } - if (c2 < c1) { - var tmp = c1; - c1 = c2; - c2 = tmp; - } - var objects = []; - var locations = []; - for (var r = r1; r <= r2; r++) { - for (var c = c1; c <= c2; c++) { - var location = getLocation(level, r, c); - locations.push(location); - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(objects, object); + if (selectionStart == null || selectionEnd == null) return []; + var rowcol1 = getRowcol(level, selectionStart); + var rowcol2 = getRowcol(level, selectionEnd); + var r1 = rowcol1.r; + var c1 = rowcol1.c; + var r2 = rowcol2.r; + var c2 = rowcol2.c; + if (r2 < r1) { + var tmp = r1; + r1 = r2; + r2 = tmp; + } + if (c2 < c1) { + var tmp = c1; + c1 = c2; + c2 = tmp; } - } - // select the rest of any partially-selected objects - objects.forEach(function(object) { - object.locations.forEach(function(location) { - addIfNotPresent(locations, location); + var objects = []; + var locations = []; + for (var r = r1; r <= r2; r++) { + for (var c = c1; c <= c2; c++) { + var location = getLocation(level, r, c); + locations.push(location); + var object = findObjectAtLocation(location); + if (object != null) addIfNotPresent(objects, object); + } + } + // select the rest of any partially-selected objects + objects.forEach(function (object) { + object.locations.forEach(function (location) { + addIfNotPresent(locations, location); + }); }); - }); - return locations; + return locations; } function setHeight(newHeight, changeLog) { - if (newHeight < level.height) { - // crop - for (var r = newHeight; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - // also delete non-space tiles - paintTileAtLocation(location, SPACE, changeLog); - } - } - level.map.splice(newHeight * level.width); - } else { - // expand - for (var r = level.height; r < newHeight; r++) { - for (var c = 0; c < level.width; c++) { - level.map.push(SPACE); - } + if (newHeight < level.height) { + // crop + for (var r = newHeight; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + removeAnyObjectAtLocation(location, changeLog); + // also delete non-space tiles + paintTileAtLocation(location, SPACE, changeLog); + } + } + level.map.splice(newHeight * level.width); + } else { + // expand + for (var r = level.height; r < newHeight; r++) { + for (var c = 0; c < level.width; c++) { + level.map.push(SPACE); + } + } } - } - changeLog.push(["h", level.height, newHeight]); - level.height = newHeight; + changeLog.push(["h", level.height, newHeight]); + level.height = newHeight; } function setWidth(newWidth, changeLog) { - if (newWidth < level.width) { - // crop - for (var r = level.height - 1; r >= 0; r--) { - for (var c = level.width - 1; c >= newWidth; c--) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, SPACE, changeLog); - level.map.splice(location, 1); - } - } - } else { - // expand - for (var r = level.height - 1; r >= 0; r--) { - var insertionPoint = level.width * (r + 1); - for (var c = level.width; c < newWidth; c++) { - // boy is this inefficient. ... YOLO! - level.map.splice(insertionPoint, 0, SPACE); - } + if (newWidth < level.width) { + // crop + for (var r = level.height - 1; r >= 0; r--) { + for (var c = level.width - 1; c >= newWidth; c--) { + var location = getLocation(level, r, c); + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, SPACE, changeLog); + level.map.splice(location, 1); + } + } + } else { + // expand + for (var r = level.height - 1; r >= 0; r--) { + var insertionPoint = level.width * (r + 1); + for (var c = level.width; c < newWidth; c++) { + // boy is this inefficient. ... YOLO! + level.map.splice(insertionPoint, 0, SPACE); + } + } } - } - var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); - level.objects.forEach(function(object) { - object.locations = object.locations.map(transformLocation); - }); + var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); + level.objects.forEach(function (object) { + object.locations = object.locations.map(transformLocation); + }); - changeLog.push(["w", level.width, newWidth]); - level.width = newWidth; + changeLog.push(["w", level.width, newWidth]); + level.width = newWidth; } function newSnake(color, location) { - var snakes = findSnakesOfColor(color); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id !== i * snakeColors.length + color) break; - } - return { - type: SNAKE, - id: i * snakeColors.length + color, - dead: false, - locations: [location], - }; + var snakes = findSnakesOfColor(color); + snakes.sort(compareId); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id !== i * snakeColors.length + color) break; + } + return { + type: SNAKE, + id: i * snakeColors.length + color, + dead: false, + locations: [location], + }; } function newBlock(location) { - var blocks = getBlocks(); - blocks.sort(compareId); - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id !== i) break; - } - return { - type: BLOCK, - id: i, - dead: false, // unused - locations: [location], - }; + var blocks = getBlocks(); + blocks.sort(compareId); + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].id !== i) break; + } + return { + type: BLOCK, + id: i, + dead: false, // unused + locations: [location], + }; } function newFruit(location) { - var fruits = getObjectsOfType(FRUIT); - fruits.sort(compareId); - for (var i = 0; i < fruits.length; i++) { - if (fruits[i].id !== i) break; - } - return { - type: FRUIT, - id: i, - dead: false, // unused - locations: [location], - }; + var fruits = getObjectsOfType(FRUIT); + fruits.sort(compareId); + for (var i = 0; i < fruits.length; i++) { + if (fruits[i].id !== i) break; + } + return { + type: FRUIT, + id: i, + dead: false, // unused + locations: [location], + }; } function newPoisonFruit(location) { - var fruits = getObjectsOfType(POISON_FRUIT); - fruits.sort(compareId); - for (var i = 0; i < fruits.length; i++) { - if (fruits[i].id !== i) break; - } - return { - type: POISON_FRUIT, - id: i, - dead: false, // unused - locations: [location], - }; + var fruits = getObjectsOfType(POISON_FRUIT); + fruits.sort(compareId); + for (var i = 0; i < fruits.length; i++) { + if (fruits[i].id !== i) break; + } + return { + type: POISON_FRUIT, + id: i, + dead: false, // unused + locations: [location], + }; } function paintAtLocation(location, changeLog) { - if (typeof paintBrushTileCode === "number") { - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, paintBrushTileCode, changeLog); - } else if (paintBrushTileCode === "resize") { - var toRowcol = getRowcol(level, location); - var dr = toRowcol.r - resizeDragAnchorRowcol.r; - var dc = toRowcol.c - resizeDragAnchorRowcol.c; - resizeDragAnchorRowcol = toRowcol; - if (dr !== 0) setHeight(level.height + dr, changeLog); - if (dc !== 0) setWidth(level.width + dc, changeLog); - } else if (paintBrushTileCode === "select") { - selectionEnd = location; - } else if (paintBrushTileCode === "paste") { - var hoverRowcol = getRowcol(level, location); - var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); - pastedData.selectedLocations.forEach(function(location) { - var tileCode = pastedData.level.map[location]; - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, tileCode, changeLog); - }); - pastedData.selectedObjects.forEach(function(object) { - // refresh the ids so there are no collisions. - if (object.type === SNAKE) { - object.id = newSnake(object.id % snakeColors.length).id; - } else if (object.type === BLOCK) { - object.id = newBlock().id; - } else if (object.type === FRUIT) { - object.id = newFruit().id; - } else if (object.type === POISON_FRUIT) { - object.id = newPoisonFruit().id; - } else throw unreachable(); - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - }); - } else if (paintBrushTileCode === SNAKE) { - var oldSnakeSerialization = serializeObjectState(paintBrushObject); - if (paintBrushObject != null) { - // keep dragging - if (paintBrushObject.locations[0] === location) return; // we just did that - // watch out for self-intersection - var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); - if (selfIntersectionIndex !== -1) { - // truncate from here back - paintBrushObject.locations.splice(selfIntersectionIndex); - } - } + if (typeof paintBrushTileCode === "number") { + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, paintBrushTileCode, changeLog); + } else if (paintBrushTileCode === "resize") { + var toRowcol = getRowcol(level, location); + var dr = toRowcol.r - resizeDragAnchorRowcol.r; + var dc = toRowcol.c - resizeDragAnchorRowcol.c; + resizeDragAnchorRowcol = toRowcol; + if (dr !== 0) setHeight(level.height + dr, changeLog); + if (dc !== 0) setWidth(level.width + dc, changeLog); + } else if (paintBrushTileCode === "select") { + selectionEnd = location; + } else if (paintBrushTileCode === "paste") { + var hoverRowcol = getRowcol(level, location); + var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); + pastedData.selectedLocations.forEach(function (location) { + var tileCode = pastedData.level.map[location]; + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, tileCode, changeLog); + }); + pastedData.selectedObjects.forEach(function (object) { + // refresh the ids so there are no collisions. + if (object.type === SNAKE) { + object.id = newSnake(object.id % snakeColors.length).id; + } else if (object.type === BLOCK) { + object.id = newBlock().id; + } else if (object.type === FRUIT) { + object.id = newFruit().id; + } else if (object.type === POISON_FRUIT) { + object.id = newPoisonFruit().id; + } else throw unreachable(); + level.objects.push(object); + changeLog.push([object.type, object.id, [0, []], serializeObjectState(object)]); + }); + } else if (paintBrushTileCode === SNAKE) { + var oldSnakeSerialization = serializeObjectState(paintBrushObject); + if (paintBrushObject != null) { + // keep dragging + if (paintBrushObject.locations[0] === location) return; // we just did that + // watch out for self-intersection + var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); + if (selfIntersectionIndex !== -1) { + // truncate from here back + paintBrushObject.locations.splice(selfIntersectionIndex); + } + } - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - if (paintBrushObject == null) { - var thereWereNoSnakes = countSnakes() === 0; - paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); - level.objects.push(paintBrushObject); - if (thereWereNoSnakes) activateAnySnakePlease(); - } else { - // extend le snake - paintBrushObject.locations.unshift(location); - } - changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); - } else if (paintBrushTileCode === BLOCK) { - var objectHere = findObjectAtLocation(location); - if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { - // just start editing this block - paintBrushBlockId = objectHere.id; - } else { - // make a change - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - var thisBlock = null; - if (paintBrushBlockId != null) { - thisBlock = findBlockById(paintBrushBlockId); - } - var oldBlockSerialization = serializeObjectState(thisBlock); - if (thisBlock == null) { - // create new block + // make sure there's space behind us + paintTileAtLocation(location, SPACE, changeLog); removeAnyObjectAtLocation(location, changeLog); - thisBlock = newBlock(location); - level.objects.push(thisBlock); - paintBrushBlockId = thisBlock.id; - } else { - var existingIndex = thisBlock.locations.indexOf(location); - if (existingIndex !== -1) { - // reclicking part of this object means to delete just part of it. - if (thisBlock.locations.length === 1) { - // goodbye - removeObject(thisBlock, changeLog); - paintBrushBlockId = null; - } else { - thisBlock.locations.splice(existingIndex, 1); - } + if (paintBrushObject == null) { + var thereWereNoSnakes = countSnakes() === 0; + paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); + level.objects.push(paintBrushObject); + if (thereWereNoSnakes) activateAnySnakePlease(); } else { - // add a tile to the block - removeAnyObjectAtLocation(location, changeLog); - thisBlock.locations.push(location); + // extend le snake + paintBrushObject.locations.unshift(location); } - } - changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); - delete blockSupportRenderCache[thisBlock.id]; - } - } else if (paintBrushTileCode === FRUIT || paintBrushTileCode === POISON_FRUIT) { - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - var object = paintBrushTileCode == FRUIT ? newFruit(location) : newPoisonFruit(location); - level.objects.push(object); - changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); - } else throw unreachable(); - render(); + changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); + } else if (paintBrushTileCode === BLOCK) { + var objectHere = findObjectAtLocation(location); + if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { + // just start editing this block + paintBrushBlockId = objectHere.id; + } else { + // make a change + // make sure there's space behind us + paintTileAtLocation(location, SPACE, changeLog); + var thisBlock = null; + if (paintBrushBlockId != null) { + thisBlock = findBlockById(paintBrushBlockId); + } + var oldBlockSerialization = serializeObjectState(thisBlock); + if (thisBlock == null) { + // create new block + removeAnyObjectAtLocation(location, changeLog); + thisBlock = newBlock(location); + level.objects.push(thisBlock); + paintBrushBlockId = thisBlock.id; + } else { + var existingIndex = thisBlock.locations.indexOf(location); + if (existingIndex !== -1) { + // reclicking part of this object means to delete just part of it. + if (thisBlock.locations.length === 1) { + // goodbye + removeObject(thisBlock, changeLog); + paintBrushBlockId = null; + } else { + thisBlock.locations.splice(existingIndex, 1); + } + } else { + // add a tile to the block + removeAnyObjectAtLocation(location, changeLog); + thisBlock.locations.push(location); + } + } + changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); + delete blockSupportRenderCache[thisBlock.id]; + } + } else if (paintBrushTileCode === FRUIT || paintBrushTileCode === POISON_FRUIT) { + paintTileAtLocation(location, SPACE, changeLog); + removeAnyObjectAtLocation(location, changeLog); + var object = paintBrushTileCode == FRUIT ? newFruit(location) : newPoisonFruit(location); + level.objects.push(object); + changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); + } else throw unreachable(); + render(); } function paintTileAtLocation(location, tileCode, changeLog) { - if (level.map[location] === tileCode) return; - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; + if (level.map[location] === tileCode) return; + changeLog.push(["m", location, level.map[location], tileCode]); + level.map[location] = tileCode; } function pushUndo(undoStuff, changeLog) { - // changeLog = [ - // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], - // // player input for snake 0, dr:-1, dc:0. has no effect on state. - // // "i" is always the first change in normal player movement. - // // if a changeLog does not start with "i", then it is an editor action. - // // animationQueue and freshlyRemovedAnimatedObjects - // // are used for animating re-move. - // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 - // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] - // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] - // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] - // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] - // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. - // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. - // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. - // 10, // the last change is always a declaration of the final width of the map. - // ]; - reduceChangeLog(changeLog); - if (changeLog.length === 0) return; - changeLog.push(level.width); - undoStuff.undoStack.push(changeLog); - undoStuff.redoStack = []; - paradoxes = []; - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; - - undoStuffChanged(undoStuff); + // changeLog = [ + // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], + // // player input for snake 0, dr:-1, dc:0. has no effect on state. + // // "i" is always the first change in normal player movement. + // // if a changeLog does not start with "i", then it is an editor action. + // // animationQueue and freshlyRemovedAnimatedObjects + // // are used for animating re-move. + // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 + // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] + // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] + // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] + // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] + // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. + // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. + // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. + // 10, // the last change is always a declaration of the final width of the map. + // ]; + reduceChangeLog(changeLog); + if (changeLog.length === 0) return; + changeLog.push(level.width); + undoStuff.undoStack.push(changeLog); + undoStuff.redoStack = []; + paradoxes = []; + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; + + undoStuffChanged(undoStuff); } function reduceChangeLog(changeLog) { - for (var i = 0; i < changeLog.length - 1; i++) { - var change = changeLog[i]; - if (change[0] === "i") { - continue; // don't reduce player input - } else if (change[0] === "h") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "h") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "w") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "w") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "w") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "h") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "m") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "m" && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (change[2] === change[3]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === change[0] && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (deepEquals(change[2], change[3])) { - // no change - changeLog.splice(i, 1); - i--; - } - } else throw unreachable(); - } + for (var i = 0; i < changeLog.length - 1; i++) { + var change = changeLog[i]; + if (change[0] === "i") { + continue; // don't reduce player input + } else if (change[0] === "h") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "h") { + // combine + change[2] = otherChange[2]; + changeLog.splice(j, 1); + j--; + continue; + } else if (otherChange[0] === "w") { + continue; // no interaction between height and width + } else break; // no more reduction possible + } + if (change[1] === change[2]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === "w") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "w") { + // combine + change[2] = otherChange[2]; + changeLog.splice(j, 1); + j--; + continue; + } else if (otherChange[0] === "h") { + continue; // no interaction between height and width + } else break; // no more reduction possible + } + if (change[1] === change[2]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === "m") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "m" && otherChange[1] === change[1]) { + // combine + change[3] = otherChange[3]; + changeLog.splice(j, 1); + j--; + } else if (otherChange[0] === "w" || otherChange[0] === "h") { + break; // can't reduce accros resizes + } + } + if (change[2] === change[3]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === change[0] && otherChange[1] === change[1]) { + // combine + change[3] = otherChange[3]; + changeLog.splice(j, 1); + j--; + } else if (otherChange[0] === "w" || otherChange[0] === "h") { + break; // can't reduce accros resizes + } + } + if (deepEquals(change[2], change[3])) { + // no change + changeLog.splice(i, 1); + i--; + } + } else throw unreachable(); + } } function undo(undoStuff) { - if (undoStuff.undoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - undoOneFrame(undoStuff); - undoStuffChanged(undoStuff); + if (undoStuff.undoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + undoOneFrame(undoStuff); + undoStuffChanged(undoStuff); } function reset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.undoStack.length > 0) { - undoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + while (undoStuff.undoStack.length > 0) { + undoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); } function undoOneFrame(undoStuff) { - var doThis = undoStuff.undoStack.pop(); - var redoChangeLog = []; - undoChanges(doThis, redoChangeLog); - if (redoChangeLog.length > 0) { - redoChangeLog.push(level.width); - undoStuff.redoStack.push(redoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; + var doThis = undoStuff.undoStack.pop(); + var redoChangeLog = []; + undoChanges(doThis, redoChangeLog); + if (redoChangeLog.length > 0) { + redoChangeLog.push(level.width); + undoStuff.redoStack.push(redoChangeLog); + } + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; } function redo(undoStuff) { - if (undoStuff.redoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - redoOneFrame(undoStuff); - undoStuffChanged(undoStuff); + if (undoStuff.redoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + redoOneFrame(undoStuff); + undoStuffChanged(undoStuff); } function redoAll(undoStuff) { - if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); - // preserve the level in the url bar. - var hash = "#level=" + currentSerializedLevel; - if (dirtyState === REPLAY_DIRTY) { - // there is a replay to save - hash += "#replay=" + compressSerialization(stringifyReplay()); - } - - var sv = "https://jmdiamond3.github.io/Snakefall-Redesign/SolutionVerification.html" + hash; - copyToClipboard(sv); + if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); + // preserve the level in the url bar. + var hash = "#level=" + currentSerializedLevel; + if (dirtyState === REPLAY_DIRTY) { + // there is a replay to save + hash += "#replay=" + compressSerialization(stringifyReplay()); + } + + var sv = "https://jmdiamond3.github.io/Snakefall-Redesign/SolutionVerification.html" + hash; + copyToClipboard(sv); } function copyToClipboard(text) { var dummy = document.createElement("textarea"); @@ -1462,199 +1462,199 @@ function copyToClipboard(text) { document.body.removeChild(dummy); } function unreset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.redoStack.length > 0) { - redoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + while (undoStuff.redoStack.length > 0) { + redoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); - // don't animate the last frame - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; + // don't animate the last frame + animationQueue = []; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = []; } function redoOneFrame(undoStuff) { - var doThis = undoStuff.redoStack.pop(); - var undoChangeLog = []; - undoChanges(doThis, undoChangeLog); - if (undoChangeLog.length > 0) { - undoChangeLog.push(level.width); - undoStuff.undoStack.push(undoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; + var doThis = undoStuff.redoStack.pop(); + var undoChangeLog = []; + undoChanges(doThis, undoChangeLog); + if (undoChangeLog.length > 0) { + undoChangeLog.push(level.width); + undoStuff.undoStack.push(undoChangeLog); + } + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; } function undoChanges(changes, changeLog) { - var widthContext = changes.pop(); - var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); - for (var i = changes.length - 1; i >= 0; i--) { - var paradoxDescription = undoChange(changes[i]); - if (paradoxDescription != null) paradoxes.push(paradoxDescription); - } - - var lastChange = changes[changes.length - 1]; - if (lastChange[0] === "i") { - // replay animation - animationQueue = lastChange[4]; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = lastChange[5]; - animationStart = new Date().getTime(); - } - - function undoChange(change) { - // note: everything here is going backwards: to -> from - if (change[0] === "i") { - // no state change, but preserve the intention. - changeLog.push(change); - return null; - } else if (change[0] === "h") { - // change height - var fromHeight = change[1]; - var toHeight = change[2]; - if (level.height !== toHeight) return "Impossible"; - setHeight(fromHeight, changeLog); - } else if (change[0] === "w") { - // change width - var fromWidth = change[1]; - var toWidth = change[2]; - if (level.width !== toWidth) return "Impossible"; - setWidth(fromWidth, changeLog); - } else if (change[0] === "m") { - // change map tile - var location = transformLocation(change[1]); - var fromTileCode = change[2]; - var toTileCode = change[3]; - if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; - if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; - paintTileAtLocation(location, fromTileCode, changeLog); - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { - // change object - var type = change[0]; - var id = change[1]; - var fromDead = change[2][0]; - var toDead = change[3][0]; - var fromLocations = change[2][1].map(transformLocation); - var toLocations = change[3][1].map(transformLocation); - if (fromLocations.filter(function(location) { return location >= level.map.length; }).length > 0) { - return "Can't move " + describe(type, id) + " out of bounds"; - } - var object = findObjectOfTypeAndId(type, id); - if (toLocations.length !== 0) { - // should exist at this location - if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; - if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; - if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; - // doit - if (fromLocations.length !== 0) { - var oldState = serializeObjectState(object); - object.locations = fromLocations; - object.dead = fromDead; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - } else { - removeObject(object, changeLog); - } - } else { - // shouldn't exist - if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; - // doit - object = { - type: type, - id: id, - dead: fromDead, - locations: fromLocations, - }; - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - } - } else throw unreachable(); - } + var widthContext = changes.pop(); + var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); + for (var i = changes.length - 1; i >= 0; i--) { + var paradoxDescription = undoChange(changes[i]); + if (paradoxDescription != null) paradoxes.push(paradoxDescription); + } + + var lastChange = changes[changes.length - 1]; + if (lastChange[0] === "i") { + // replay animation + animationQueue = lastChange[4]; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = lastChange[5]; + animationStart = new Date().getTime(); + } + + function undoChange(change) { + // note: everything here is going backwards: to -> from + if (change[0] === "i") { + // no state change, but preserve the intention. + changeLog.push(change); + return null; + } else if (change[0] === "h") { + // change height + var fromHeight = change[1]; + var toHeight = change[2]; + if (level.height !== toHeight) return "Impossible"; + setHeight(fromHeight, changeLog); + } else if (change[0] === "w") { + // change width + var fromWidth = change[1]; + var toWidth = change[2]; + if (level.width !== toWidth) return "Impossible"; + setWidth(fromWidth, changeLog); + } else if (change[0] === "m") { + // change map tile + var location = transformLocation(change[1]); + var fromTileCode = change[2]; + var toTileCode = change[3]; + if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; + if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; + paintTileAtLocation(location, fromTileCode, changeLog); + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { + // change object + var type = change[0]; + var id = change[1]; + var fromDead = change[2][0]; + var toDead = change[3][0]; + var fromLocations = change[2][1].map(transformLocation); + var toLocations = change[3][1].map(transformLocation); + if (fromLocations.filter(function (location) { return location >= level.map.length; }).length > 0) { + return "Can't move " + describe(type, id) + " out of bounds"; + } + var object = findObjectOfTypeAndId(type, id); + if (toLocations.length !== 0) { + // should exist at this location + if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; + if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; + if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; + // doit + if (fromLocations.length !== 0) { + var oldState = serializeObjectState(object); + object.locations = fromLocations; + object.dead = fromDead; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + } else { + removeObject(object, changeLog); + } + } else { + // shouldn't exist + if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; + // doit + object = { + type: type, + id: id, + dead: fromDead, + locations: fromLocations, + }; + level.objects.push(object); + changeLog.push([object.type, object.id, [0, []], serializeObjectState(object)]); + } + } else throw unreachable(); + } } function describe(arg1, arg2) { - // describe(0) -> "Space" - // describe(SNAKE, 0) -> "Snake 0 (Red)" - // describe(object) -> "Snake 0 (Red)" - // describe(BLOCK, 1) -> "Block 1" - // describe(FRUIT) -> "Fruit" - if (typeof arg1 === "number") { - switch (arg1) { - case SPACE: return "Space"; - case WALL: return "a Wall"; - case SPIKE: return "Spikes"; - case EXIT: return "an Exit"; - case PORTAL: return "a Portal"; - case PLATFORM: return "a Platform"; - case WOODPLATFORM: return "a Wooden Platform"; - case ONEWAYWALLU: return "a One Way Wall (facing U)"; - case ONEWAYWALLD: return "a One Way Wall (facing D)"; - case ONEWAYWALLL: return "a One Way Wall (facing L)"; - case ONEWAYWALLR: return "a One Way Wall (facing R)"; - case CLOSEDLIFT: return "a Closed Lift"; - case OPENLIFT: return "an Open Lift"; - case CLOUD: return "a Cloud"; - case BUBBLE: return "a Bubble"; - case LAVA: return "Lava"; - case WATER: return "Water"; - default: throw unreachable(); + // describe(0) -> "Space" + // describe(SNAKE, 0) -> "Snake 0 (Red)" + // describe(object) -> "Snake 0 (Red)" + // describe(BLOCK, 1) -> "Block 1" + // describe(FRUIT) -> "Fruit" + if (typeof arg1 === "number") { + switch (arg1) { + case SPACE: return "Space"; + case WALL: return "a Wall"; + case SPIKE: return "Spikes"; + case EXIT: return "an Exit"; + case PORTAL: return "a Portal"; + case PLATFORM: return "a Platform"; + case WOODPLATFORM: return "a Wooden Platform"; + case ONEWAYWALLU: return "a One Way Wall (facing U)"; + case ONEWAYWALLD: return "a One Way Wall (facing D)"; + case ONEWAYWALLL: return "a One Way Wall (facing L)"; + case ONEWAYWALLR: return "a One Way Wall (facing R)"; + case CLOSEDLIFT: return "a Closed Lift"; + case OPENLIFT: return "an Open Lift"; + case CLOUD: return "a Cloud"; + case BUBBLE: return "a Bubble"; + case LAVA: return "Lava"; + case WATER: return "Water"; + default: throw unreachable(); + } + } + if (arg1 === SNAKE) { + var color = (function () { + switch (snakeColors[arg2 % snakeColors.length]) { + case "#fd0c0b": return " (Red)"; + case "#18d11f": return " (Green)"; + case "#004cff": return " (Blue)"; + case "#fdc122": return " (Yellow)"; + default: throw unreachable(); + } + })(); + return "Snake " + arg2 + color; + } + if (arg1 === BLOCK) { + return "Block " + arg2; + } + if (arg1 === FRUIT) { + return "Fruit"; + } + if (arg1 === POISON_FRUIT) { + return "Poison Fruit"; } - } - if (arg1 === SNAKE) { - var color = (function() { - switch (snakeColors[arg2 % snakeColors.length]) { - case "#fd0c0b": return " (Red)"; - case "#18d11f": return " (Green)"; - case "#004cff": return " (Blue)"; - case "#fdc122": return " (Yellow)"; - default: throw unreachable(); - } - })(); - return "Snake " + arg2 + color; - } - if (arg1 === BLOCK) { - return "Block " + arg2; - } - if (arg1 === FRUIT) { - return "Fruit"; - } - if (arg1 === POISON_FRUIT) { - return "Poison Fruit"; - } - if (typeof arg1 === "object") return describe(arg1.type, arg1.id); - throw unreachable(); + if (typeof arg1 === "object") return describe(arg1.type, arg1.id); + throw unreachable(); } function undoStuffChanged(undoStuff) { - var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; - document.getElementById(undoStuff.spanId).textContent = movesText; - document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; - document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; - - // render paradox display - var uniqueParadoxes = []; - var paradoxCounts = []; - paradoxes.forEach(function(paradoxDescription) { - var index = uniqueParadoxes.indexOf(paradoxDescription); - if (index !== -1) { - paradoxCounts[index] += 1; - } else { - uniqueParadoxes.push(paradoxDescription); - paradoxCounts.push(1); + var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; + document.getElementById(undoStuff.spanId).textContent = movesText; + document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; + document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; + + // render paradox display + var uniqueParadoxes = []; + var paradoxCounts = []; + paradoxes.forEach(function (paradoxDescription) { + var index = uniqueParadoxes.indexOf(paradoxDescription); + if (index !== -1) { + paradoxCounts[index] += 1; + } else { + uniqueParadoxes.push(paradoxDescription); + paradoxCounts.push(1); + } + }); + var paradoxDivContent = ""; + uniqueParadoxes.forEach(function (paradox, i) { + if (i > 0) paradoxDivContent += "
    \n"; + if (paradoxCounts[i] > 1) paradoxDivContent += "(" + paradoxCounts[i] + "x) "; + paradoxDivContent += "Time Travel Paradox! " + uniqueParadoxes[i]; + }); + document.getElementById("paradoxDiv").innerHTML = paradoxDivContent; + + updateDirtyState(); + + if (unmoveStuff.redoStack.length === 0) { + document.getElementById("removeButton").classList.remove("click-me"); } - }); - var paradoxDivContent = ""; - uniqueParadoxes.forEach(function(paradox, i) { - if (i > 0) paradoxDivContent += "
    \n"; - if (paradoxCounts[i] > 1) paradoxDivContent += "(" + paradoxCounts[i] + "x) "; - paradoxDivContent += "Time Travel Paradox! " + uniqueParadoxes[i]; - }); - document.getElementById("paradoxDiv").innerHTML = paradoxDivContent; - - updateDirtyState(); - - if (unmoveStuff.redoStack.length === 0) { - document.getElementById("removeButton").classList.remove("click-me"); - } } var CLEAN_NO_TIMELINES = 0; @@ -1664,70 +1664,70 @@ var EDITOR_DIRTY = 3; var dirtyState = CLEAN_NO_TIMELINES; var editorHasBeenTouched = false; function updateDirtyState() { - if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { - dirtyState = EDITOR_DIRTY; - } else if (unmoveStuff.undoStack.length > 0) { - dirtyState = REPLAY_DIRTY; - } else if (unmoveStuff.redoStack.length > 0) { - dirtyState = CLEAN_WITH_REDO; - } else { - dirtyState = CLEAN_NO_TIMELINES; - } - - var saveLevelButton = document.getElementById("saveLevelButton"); - // the save button clears your timelines - saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; - if (dirtyState >= EDITOR_DIRTY) { - // you should save - saveLevelButton.classList.add("click-me"); - } else { - saveLevelButton.classList.remove("click-me"); - } - - var saveProgressButton = document.getElementById("saveProgressButton"); - // you can't save a replay if your level is dirty - if (dirtyState === CLEAN_WITH_REDO) { - saveProgressButton.textContent = "Forget Progress"; - } else { - saveProgressButton.textContent = "Save Progress"; - } - saveProgressButton.disabled = dirtyState >= EDITOR_DIRTY || dirtyState === CLEAN_NO_TIMELINES; + if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { + dirtyState = EDITOR_DIRTY; + } else if (unmoveStuff.undoStack.length > 0) { + dirtyState = REPLAY_DIRTY; + } else if (unmoveStuff.redoStack.length > 0) { + dirtyState = CLEAN_WITH_REDO; + } else { + dirtyState = CLEAN_NO_TIMELINES; + } + + var saveLevelButton = document.getElementById("saveLevelButton"); + // the save button clears your timelines + saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; + if (dirtyState >= EDITOR_DIRTY) { + // you should save + saveLevelButton.classList.add("click-me"); + } else { + saveLevelButton.classList.remove("click-me"); + } + + var saveProgressButton = document.getElementById("saveProgressButton"); + // you can't save a replay if your level is dirty + if (dirtyState === CLEAN_WITH_REDO) { + saveProgressButton.textContent = "Forget Progress"; + } else { + saveProgressButton.textContent = "Save Progress"; + } + saveProgressButton.disabled = dirtyState >= EDITOR_DIRTY || dirtyState === CLEAN_NO_TIMELINES; } function haveCheatcodesBeenUsed() { - return !unmoveStuff.undoStack.every(function(changeLog) { - // normal movement always starts with "i". - return changeLog[0][0] === "i"; - }); + return !unmoveStuff.undoStack.every(function (changeLog) { + // normal movement always starts with "i". + return changeLog[0][0] === "i"; + }); } var persistentState = { - showEditor: false, - showGrid: false, + showEditor: false, + showGrid: false, }; function savePersistentState() { - localStorage.snakefall = JSON.stringify(persistentState); + localStorage.snakefall = JSON.stringify(persistentState); } function loadPersistentState() { - try { - persistentState = JSON.parse(localStorage.snakefall); - } catch (e) { - } - persistentState.showEditor = !!persistentState.showEditor; - persistentState.showGrid = !!persistentState.showGrid; - showEditorChanged(); + try { + persistentState = JSON.parse(localStorage.snakefall); + } catch (e) { + } + persistentState.showEditor = !!persistentState.showEditor; + persistentState.showGrid = !!persistentState.showGrid; + showEditorChanged(); } var isGravityEnabled = true; function isGravity() { - return isGravityEnabled || !persistentState.showEditor; + return isGravityEnabled || !persistentState.showEditor; } var isCollisionEnabled = true; function isCollision() { - return isCollisionEnabled || !persistentState.showEditor; + return isCollisionEnabled || !persistentState.showEditor; } function isAnyCheatcodeEnabled() { - return persistentState.showEditor && ( - !isGravityEnabled || !isCollisionEnabled - ); + return persistentState.showEditor && ( + !isGravityEnabled || !isCollisionEnabled + ); } var themeName = "Spring"; //Gooby var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle, experimentalColors; @@ -1742,31 +1742,31 @@ var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; var snakeColors2 = ["#f00", "#0f0", "#00f", "#ff0"]; var snakeColors3 = ["#BA145C", "#E91624", "#F75802", "#FEFE28"]; -var fruitColors1 = ["#ff0066","#ff36a6","#ff6b1f","#ff9900","#ff2600"]; -var fruitColors2 = ["black","black","black","black","black"]; +var fruitColors1 = ["#ff0066", "#ff36a6", "#ff6b1f", "#ff9900", "#ff2600"]; +var fruitColors2 = ["black", "black", "black", "black", "black"]; var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spike, support, box, bolt var spikeColors2 = ["gray", "black", "white", "black"]; var spikeColors3 = ["#333", "#333", "#333", "#777"]; var blockColors1 = [ - ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"], - ["#853641","#963c84","#753d88","#5d3a96","#3a3990"] + ["#de5a6d", "#fa65dd", "#c367e3", "#9c62fa", "#625ff0"], + ["#853641", "#963c84", "#753d88", "#5d3a96", "#3a3990"] ]; var blockColors2 = [ ["#999"], ["#999"] ]; var blockColors3 = [ - ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"], - ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] + ["#de7913", "#7d46a0", "#39868b", "#41ccc2", "#ded800"], + ["#8d4d0c", "#532f6a", "#2c686d", "#207973", "#999400"] ]; var blockColors4 = [ ["#150612", "#a52e8b", "#990077", "#d917af", "#4d003c"], - ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] + ["#8d4d0c", "#532f6a", "#2c686d", "#207973", "#999400"] ]; -var fontSize = tileSize*5; +var fontSize = tileSize * 5; var textStyle1 = ["" + fontSize + "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose var textStyle2 = ["" + fontSize + "px Impact", "#5702c6", "#ff0098"]; var textStyle3 = ["" + fontSize + "px Impact", "#BA145C", "#F75802"]; @@ -1778,547 +1778,542 @@ var experimentalColors2 = ["white", "#FEFE28"]; var themeCounter = 0; var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor, textStyle, experimentalColors - //["sky",], - ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], - ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], - ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], - ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] + //["sky",], + ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], + ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], + ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], + ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], + ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], + ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] ]; function showEditorChanged() { - document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; - ["editorDiv", "editorPane"].forEach(function(id) { - document.getElementById(id).style.display = persistentState.showEditor ? "block" : "none"; - }); - document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : "/WASD"; + document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; + ["editorDiv", "editorPane"].forEach(function (id) { + document.getElementById(id).style.display = persistentState.showEditor ? "block" : "none"; + }); + document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : "/WASD"; - render(); + render(); } function move(dr, dc) { - if (!isAlive()) return; - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; - animationStart = new Date().getTime(); - var activeSnake = findActiveSnake(); - var headRowcol = getRowcol(level, activeSnake.locations[0]); - var newRowcol = {r:headRowcol.r + dr, c:headRowcol.c + dc}; - if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; - var newLocation = getLocation(level, newRowcol.r, newRowcol.c); - var changeLog = []; - - // The changeLog for a player movement starts with the input - // when playing normally. - if (!isAnyCheatcodeEnabled()) { - changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); - } - - var ate = false; - var ate_poison = false; - var pushedObjects = []; - - //track ClosedLifts that had objects on them - var occupiedClosedLift = getOccupiedClosedLiftLocations(); - - if (isCollision()) { - var newTile = level.map[newLocation]; - if (newTile === BUBBLE || newTile === CLOUD) - paintTileAtLocation(newLocation, SPACE, changeLog); - else if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile - var otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { - if (otherObject === activeSnake) return; // can't push yourself - if (otherObject.type === FRUIT) { - // eat - removeObject(otherObject, changeLog); - ate = true; - } else if (otherObject.type === POISON_FRUIT) { - // eat poison - removeObject(otherObject, changeLog); - ate_poison = true; - } else if (isTileCodeAir(activeSnake, null, newTile, dr, dc)) { - otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { - if (otherObject === activeSnake) return; // can't push yourself - // push objects - if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; - } - } else return; // can't go through that tile + if (!isAlive()) return; + animationQueue = []; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = []; + animationStart = new Date().getTime(); + var activeSnake = findActiveSnake(); + var headRowcol = getRowcol(level, activeSnake.locations[0]); + var newRowcol = { r: headRowcol.r + dr, c: headRowcol.c + dc }; + if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; + var newLocation = getLocation(level, newRowcol.r, newRowcol.c); + var changeLog = []; + + // The changeLog for a player movement starts with the input + // when playing normally. + if (!isAnyCheatcodeEnabled()) { + changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); } - } - - // slither forward - var activeSnakeOldState = serializeObjectState(activeSnake); - var size1 = activeSnake.locations.length === 1; - var slitherAnimations = [ - 70, - [ - // size-1 snakes really do more of a move than a slither - size1 ? MOVE_SNAKE : SLITHER_HEAD, - activeSnake.id, - dr, - dc, - ] - ]; - activeSnake.locations.unshift(newLocation); - - // drag your tail forward based on what was/wasn't eaten - var times = 1; - if (ate) { times--; } - if (ate_poison) { times++; } - //if we're going to shrink out of existence, prevent it - var snake_length = activeSnake.locations.length-1; - if (times > snake_length) - { - times = snake_length; - activeSnake.dead = true; - //make the snake appear to vanish into non-existence - activeSnake.locations[0] = {r:-99, c:-99}; - } - for (var t = 0; t < times; ++t) { - for(var i = 1; i snake_length) { + times = snake_length; + activeSnake.dead = true; + //make the snake appear to vanish into non-existence + activeSnake.locations[0] = { r: -99, c: -99 }; + } + for (var t = 0; t < times; ++t) { + for (var i = 1; i < activeSnake.locations.length; i++) { + // drag your tail forward + var oldRowcol = getRowcol(level, activeSnake.locations[i + 1]); + newRowcol = getRowcol(level, activeSnake.locations[i]); + if (!size1) { + slitherAnimations.push([ + SLITHER_TAIL, + activeSnake.id, + newRowcol.r - oldRowcol.r, + newRowcol.c - oldRowcol.c, + ]); + } } - } + activeSnake.locations.pop(); } - - occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); + changeLog.push([activeSnake.type, activeSnake.id, activeSnakeOldState, serializeObjectState(activeSnake)]); - // fall - var dyingObjects = []; - var fallingObjects = level.objects.filter(function(object) { - if (object.type === FRUIT || object.type === POISON_FRUIT) return; // can't fall - var theseDyingObjects = []; - if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; - // this object can fall. maybe more will fall with it too. we'll check those separately. - theseDyingObjects.forEach(function(object) { - addIfNotPresent(dyingObjects, object); - }); - return true; - }); - if (dyingObjects.length > 0) { - var anySnakesDied = false; - dyingObjects.forEach(function(object) { - if (object.type === SNAKE) { - // look what you've done - var oldState = serializeObjectState(object); - object.dead = true; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - anySnakesDied = true; - } else if (object.type === BLOCK) { - // a box fell off the world - removeAnimatedObject(object, changeLog); - removeFromArray(fallingObjects, object); - exitAnimationQueue.push([ - 200, - [ - DIE_BLOCK, - object.id, - 0, 0 - ], - ]); - didAnything = true; - } else throw unreachable(); - }); - if (anySnakesDied) break; + // did you just push your face into a portal? + var portalLocations = getActivePortalLocations(); + var portalActivationLocations = []; + if (portalLocations.indexOf(newLocation) !== -1) { + portalActivationLocations.push(newLocation); } - if (fallingObjects.length > 0) { - moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); - didAnything = true; - } - - occupiedClosedLift = openLift(occupiedClosedLift, changeLog); + // push everything, too + moveObjects(pushedObjects, dr, dc, portalLocations, portalActivationLocations, changeLog, slitherAnimations); + animationQueue.push(slitherAnimations); + + occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); + + // gravity loop + var stateToAnimationIndex = {}; + if (isGravity()) for (var fallHeight = 1; ; fallHeight++) { + var serializedState = serializeObjects(level.objects); + var infiniteLoopStartIndex = stateToAnimationIndex[serializedState]; + if (infiniteLoopStartIndex != null) { + // infinite loop + animationQueue.push([0, [INFINITE_LOOP, animationQueue.length - infiniteLoopStartIndex]]); + break; + } else { + stateToAnimationIndex[serializedState] = animationQueue.length; + } + // do portals separate from falling logic + if (portalActivationLocations.length === 1) { + var portalAnimations = [500]; + if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { + animationQueue.push(portalAnimations); + } + portalActivationLocations = []; + } + // now do falling logic + var didAnything = false; + var fallingAnimations = [ + 70 / Math.sqrt(fallHeight), + ]; + var exitAnimationQueue = []; + + // check for exit + if (!isUneatenFruit()) { //Gooby + var snakes = getSnakes(); + for (var i = 0; i < snakes.length; i++) { + var snake = snakes[i]; + if (level.map[snake.locations[0]] === EXIT) { + // (one of) you made it! + removeAnimatedObject(snake, changeLog); + exitAnimationQueue.push([ + 200, + [EXIT_SNAKE, snake.id, 0, 0], + ]); + didAnything = true; + } + } + } + + occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); + + // fall + var dyingObjects = []; + var fallingObjects = level.objects.filter(function (object) { + if (object.type === FRUIT || object.type === POISON_FRUIT) return; // can't fall + var theseDyingObjects = []; + if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; + // this object can fall. maybe more will fall with it too. we'll check those separately. + theseDyingObjects.forEach(function (object) { + addIfNotPresent(dyingObjects, object); + }); + return true; + }); + if (dyingObjects.length > 0) { + var anySnakesDied = false; + dyingObjects.forEach(function (object) { + if (object.type === SNAKE) { + // look what you've done + var oldState = serializeObjectState(object); + object.dead = true; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + anySnakesDied = true; + } else if (object.type === BLOCK) { + // a box fell off the world + removeAnimatedObject(object, changeLog); + removeFromArray(fallingObjects, object); + exitAnimationQueue.push([ + 200, + [ + DIE_BLOCK, + object.id, + 0, 0 + ], + ]); + didAnything = true; + } else throw unreachable(); + }); + if (anySnakesDied) break; + } + if (fallingObjects.length > 0) { + moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); + didAnything = true; + } + + occupiedClosedLift = openLift(occupiedClosedLift, changeLog); - if (!didAnything) break; - Array.prototype.push.apply(animationQueue, exitAnimationQueue); - if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); - } + if (!didAnything) break; + Array.prototype.push.apply(animationQueue, exitAnimationQueue); + if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); + } - pushUndo(unmoveStuff, changeLog); - render(); + pushUndo(unmoveStuff, changeLog); + render(); } -function combineOldAndNewLiftOccupations(oldOccupiedClosedLift) -{ - var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); - var newlyOccupiedClosedLift = getSetSubtract(newOccupiedClosedLift, oldOccupiedClosedLift); - return oldOccupiedClosedLift.concat(newlyOccupiedClosedLift); +function combineOldAndNewLiftOccupations(oldOccupiedClosedLift) { + var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); + var newlyOccupiedClosedLift = getSetSubtract(newOccupiedClosedLift, oldOccupiedClosedLift); + return oldOccupiedClosedLift.concat(newlyOccupiedClosedLift); } -function openLift(oldOccupiedClosedLift, changeLog) -{ - var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); - var nowUnoccupiedClosedLift = getSetSubtract(oldOccupiedClosedLift, newOccupiedClosedLift); - for (var i = 0; i < nowUnoccupiedClosedLift.length; i++) { - paintTileAtLocation(nowUnoccupiedClosedLift[i], OPENLIFT, changeLog); - } - return newOccupiedClosedLift; +function openLift(oldOccupiedClosedLift, changeLog) { + var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); + var nowUnoccupiedClosedLift = getSetSubtract(oldOccupiedClosedLift, newOccupiedClosedLift); + for (var i = 0; i < nowUnoccupiedClosedLift.length; i++) { + paintTileAtLocation(nowUnoccupiedClosedLift[i], OPENLIFT, changeLog); + } + return newOccupiedClosedLift; } function getSetSubtract(array1, array2) { - if (array1.length === 0) return []; - return array1.filter(function(x) { return array2.indexOf(x) == -1; }); + if (array1.length === 0) return []; + return array1.filter(function (x) { return array2.indexOf(x) == -1; }); } function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects) { - // pusher can be null (for gravity) - pushedObjects.push(pushedObject); - // find forward locations - var forwardLocations = []; - for (var i = 0; i < pushedObjects.length; i++) { - pushedObject = pushedObjects[i]; - for (var j = 0; j < pushedObject.locations.length; j++) { - var rowcol = getRowcol(level, pushedObject.locations[j]); - var forwardRowcol = {r:rowcol.r + dr, c:rowcol.c + dc}; - if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { - if (dyingObjects == null) { - // can't push things out of bounds - return false; - } else { - // this thing is going to fall out of bounds - addIfNotPresent(dyingObjects, pushedObject); - addIfNotPresent(pushedObjects, pushedObject); - continue; - } - } - var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); - if (dr === 1 && level.map[forwardLocation] === PLATFORM) { - // this platform holds us, unless we're going through it - var neighborLocations; - if (pushedObject.type === SNAKE) { - neighborLocations = []; - if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); - if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); - } else if (pushedObject.type === BLOCK) { - neighborLocations = pushedObject.locations; - } else throw asdf; - if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface - // we slip right past it - } - var yetAnotherObject = findObjectAtLocation(forwardLocation); - if (yetAnotherObject != null) { - if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === POISON_FRUIT) { - // not pushable - return false; - } - if (yetAnotherObject === pusher) { - // indirect pushing ourselves. - // special check for when we're indirectly pushing the tip of our own tail. - if (forwardLocation === pusher.locations[pusher.locations.length -1]) { - // for some reason this is ok. ------------ THIS IS THE TAIL GLITCH - continue; - } - return false; + // pusher can be null (for gravity) + pushedObjects.push(pushedObject); + // find forward locations + var forwardLocations = []; + for (var i = 0; i < pushedObjects.length; i++) { + pushedObject = pushedObjects[i]; + for (var j = 0; j < pushedObject.locations.length; j++) { + var rowcol = getRowcol(level, pushedObject.locations[j]); + var forwardRowcol = { r: rowcol.r + dr, c: rowcol.c + dc }; + if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { + if (dyingObjects == null) { + // can't push things out of bounds + return false; + } else { + // this thing is going to fall out of bounds + addIfNotPresent(dyingObjects, pushedObject); + addIfNotPresent(pushedObjects, pushedObject); + continue; + } + } + var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); + if (dr === 1 && level.map[forwardLocation] === PLATFORM) { + // this platform holds us, unless we're going through it + var neighborLocations; + if (pushedObject.type === SNAKE) { + neighborLocations = []; + if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); + if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); + } else if (pushedObject.type === BLOCK) { + neighborLocations = pushedObject.locations; + } else throw asdf; + if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface + // we slip right past it + } + var yetAnotherObject = findObjectAtLocation(forwardLocation); + if (yetAnotherObject != null) { + if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === POISON_FRUIT) { + // not pushable + return false; + } + if (yetAnotherObject === pusher) { + // indirect pushing ourselves. + // special check for when we're indirectly pushing the tip of our own tail. + if (forwardLocation === pusher.locations[pusher.locations.length - 1]) { + // for some reason this is ok. ------------ THIS IS THE TAIL GLITCH + continue; + } + return false; + } + addIfNotPresent(pushedObjects, yetAnotherObject); + if (level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work + } else + addIfNotPresent(forwardLocations, forwardLocation); } - addIfNotPresent(pushedObjects, yetAnotherObject); - if(level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work - } else - addIfNotPresent(forwardLocations, forwardLocation); } - } - // check forward locations - for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform, saw no effect but left new code - var forwardLocation = forwardLocations[i]; - // many of these locations can be inside objects, - // but that means the tile must be air, - // and we already know pushing that object. - var tileCode = level.map[forwardLocation]; - var object = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); - if (!isTileCodeAir(pusher, object, tileCode, dr, dc)) { - if (dyingObjects != null) { - if (tileCode === SPIKE) { - // uh... which object was this again? - if (object.type === SNAKE) { - // ouch! - addIfNotPresent(dyingObjects, object); - continue; - } - - } - else if (tileCode === LAVA) { - if (object.type === SNAKE || object.type === BLOCK) { - addIfNotPresent(dyingObjects, object); - continue; - } - } - else if (tileCode === WATER) { - if (object.type === BLOCK) { - addIfNotPresent(dyingObjects, object); - continue; + // check forward locations + for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform, saw no effect but left new code + var forwardLocation = forwardLocations[i]; + // many of these locations can be inside objects, + // but that means the tile must be air, + // and we already know pushing that object. + var tileCode = level.map[forwardLocation]; + var object = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); + if (!isTileCodeAir(pusher, object, tileCode, dr, dc)) { + if (dyingObjects != null) { + if (tileCode === SPIKE) { + // uh... which object was this again? + if (object.type === SNAKE) { + // ouch! + addIfNotPresent(dyingObjects, object); + continue; + } + + } + else if (tileCode === LAVA) { + if (object.type === SNAKE || object.type === BLOCK) { + addIfNotPresent(dyingObjects, object); + continue; + } + } + else if (tileCode === WATER) { + if (object.type === BLOCK) { + addIfNotPresent(dyingObjects, object); + continue; + } + } } + // can't push into something solid + return false; } - } - // can't push into something solid - return false; } - } - // the push is go - return true; + // the push is go + return true; } function activateAnySnakePlease() { - var snakes = getSnakes(); - if (snakes.length === 0) return; // nope.avi - activeSnakeId = snakes[0].id; + var snakes = getSnakes(); + if (snakes.length === 0) return; // nope.avi + activeSnakeId = snakes[0].id; } function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations, changeLog, animations) { - objects.forEach(function(object) { - var oldState = serializeObjectState(object); - var oldPortals = getSetIntersection(portalLocations, object.locations); - for (var i = 0; i < object.locations.length; i++) { - object.locations[i] = offsetLocation(object.locations[i], dr, dc); - if (level.map[object.locations[i]] == BUBBLE || level.map[object.locations[i]] == CLOUD) - paintTileAtLocation(object.locations[i], SPACE, changeLog); - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - animations.push([ - "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK - object.id, - dr, - dc, - ]); - - var newPortals = getSetIntersection(portalLocations, object.locations); - var activatingPortals = newPortals.filter(function(portalLocation) { - return oldPortals.indexOf(portalLocation) === -1; + objects.forEach(function (object) { + var oldState = serializeObjectState(object); + var oldPortals = getSetIntersection(portalLocations, object.locations); + for (var i = 0; i < object.locations.length; i++) { + object.locations[i] = offsetLocation(object.locations[i], dr, dc); + if (level.map[object.locations[i]] == BUBBLE || level.map[object.locations[i]] == CLOUD) + paintTileAtLocation(object.locations[i], SPACE, changeLog); + } + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + animations.push([ + "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK + object.id, + dr, + dc, + ]); + + var newPortals = getSetIntersection(portalLocations, object.locations); + var activatingPortals = newPortals.filter(function (portalLocation) { + return oldPortals.indexOf(portalLocation) === -1; + }); + if (activatingPortals.length === 1) { + // exactly one new portal we're touching. activate it + portalActivationLocations.push(activatingPortals[0]); + } }); - if (activatingPortals.length === 1) { - // exactly one new portal we're touching. activate it - portalActivationLocations.push(activatingPortals[0]); - } - }); } function activatePortal(portalLocations, portalLocation, animations, changeLog) { - var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; - var portalRowcol = getRowcol(level, portalLocation); - var otherPortalRowcol = getRowcol(level, otherPortalLocation); - var delta = {r:otherPortalRowcol.r - portalRowcol.r, c:otherPortalRowcol.c - portalRowcol.c}; - - var object = findObjectAtLocation(portalLocation); - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r + delta.r; - var c = rowcol.c + delta.c; - if (!isInBounds(level, r, c)) return false; // out of bounds - newLocations.push(getLocation(level, r, c)); - } - - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile - var otherObject = findObjectAtLocation(location); - if (otherObject != null && otherObject !== object) return; // blocked by object - } - - // zappo presto! - var oldState = serializeObjectState(object); - object.locations = newLocations; - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (level.map[location] == BUBBLE || level.map[location] == CLOUD) //changed this despite bubble working perfectly without it - paintTileAtLocation(location, SPACE, changeLog); - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; + var portalRowcol = getRowcol(level, portalLocation); + var otherPortalRowcol = getRowcol(level, otherPortalLocation); + var delta = { r: otherPortalRowcol.r - portalRowcol.r, c: otherPortalRowcol.c - portalRowcol.c }; + + var object = findObjectAtLocation(portalLocation); + var newLocations = []; + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r + delta.r; + var c = rowcol.c + delta.c; + if (!isInBounds(level, r, c)) return false; // out of bounds + newLocations.push(getLocation(level, r, c)); + } + + for (var i = 0; i < newLocations.length; i++) { + var location = newLocations[i]; + if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile + var otherObject = findObjectAtLocation(location); + if (otherObject != null && otherObject !== object) return; // blocked by object + } + + // zappo presto! + var oldState = serializeObjectState(object); + object.locations = newLocations; + for (var i = 0; i < newLocations.length; i++) { + var location = newLocations[i]; + if (level.map[location] == BUBBLE || level.map[location] == CLOUD) //changed this despite bubble working perfectly without it + paintTileAtLocation(location, SPACE, changeLog); + } + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); } function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { - switch (tileCode) - { - case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; - case WOODPLATFORM: case BUBBLE: return pusher != null; - case PLATFORM: return dr != 1; - case ONEWAYWALLU: return dr != 1; - case ONEWAYWALLD: return dr != -1; - case ONEWAYWALLL: return dc != 1; - case ONEWAYWALLR: return dc != -1; - default: return false; - } + switch (tileCode) { + case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; + case WOODPLATFORM: case BUBBLE: return pusher != null; + case PLATFORM: return dr != 1; + case ONEWAYWALLU: return dr != 1; + case ONEWAYWALLD: return dr != -1; + case ONEWAYWALLL: return dc != 1; + case ONEWAYWALLR: return dc != -1; + default: return false; + } } function addIfNotPresent(array, element) { - if (array.indexOf(element) !== -1) return; - array.push(element); + if (array.indexOf(element) !== -1) return; + array.push(element); } function removeAnyObjectAtLocation(location, changeLog) { - var object = findObjectAtLocation(location); - if (object != null) removeObject(object, changeLog); + var object = findObjectAtLocation(location); + if (object != null) removeObject(object, changeLog); } function removeAnimatedObject(object, changeLog) { - removeObject(object, changeLog); - freshlyRemovedAnimatedObjects.push(object); + removeObject(object, changeLog); + freshlyRemovedAnimatedObjects.push(object); } function removeObject(object, changeLog) { - removeFromArray(level.objects, object); - changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0,[]]]); - if (object.type === SNAKE && object.id === activeSnakeId) { - activateAnySnakePlease(); - } - if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { - // no longer editing an object that doesn't exit - paintBrushBlockId = null; - } - if (object.type === BLOCK) { - delete blockSupportRenderCache[object.id]; - } + removeFromArray(level.objects, object); + changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0, []]]); + if (object.type === SNAKE && object.id === activeSnakeId) { + activateAnySnakePlease(); + } + if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { + // no longer editing an object that doesn't exit + paintBrushBlockId = null; + } + if (object.type === BLOCK) { + delete blockSupportRenderCache[object.id]; + } } function removeFromArray(array, element) { - var index = array.indexOf(element); - if (index === -1) throw unreachable(); - array.splice(index, 1); + var index = array.indexOf(element); + if (index === -1) throw unreachable(); + array.splice(index, 1); } function findActiveSnake() { - var snakes = getSnakes(); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) return snakes[i]; - } - throw unreachable(); + var snakes = getSnakes(); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) return snakes[i]; + } + throw unreachable(); } function findBlockById(id) { - return findObjectOfTypeAndId(BLOCK, id); + return findObjectOfTypeAndId(BLOCK, id); } function findSnakesOfColor(color) { - return level.objects.filter(function(object) { - if (object.type !== SNAKE) return false; - return object.id % snakeColors.length === color; - }); + return level.objects.filter(function (object) { + if (object.type !== SNAKE) return false; + return object.id % snakeColors.length === color; + }); } function findObjectOfTypeAndId(type, id) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.type === type && object.id === id) return object; - } - return null; + for (var i = 0; i < level.objects.length; i++) { + var object = level.objects[i]; + if (object.type === type && object.id === id) return object; + } + return null; } function findObjectAtLocation(location) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.locations.indexOf(location) !== -1) - return object; - } - return null; + for (var i = 0; i < level.objects.length; i++) { + var object = level.objects[i]; + if (object.locations.indexOf(location) !== -1) + return object; + } + return null; } function isUneatenFruit() { - return getObjectsOfType(FRUIT).length > 0 || getObjectsOfType(POISON_FRUIT).length > 0; + return getObjectsOfType(FRUIT).length > 0 || getObjectsOfType(POISON_FRUIT).length > 0; } function getActivePortalLocations() { - var portalLocations = getPortalLocations(); - if (portalLocations.length !== 2) return []; // nice try - return portalLocations; + var portalLocations = getPortalLocations(); + if (portalLocations.length !== 2) return []; // nice try + return portalLocations; } function getPortalLocations() { - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === PORTAL) result.push(i); - } - return result; + var result = []; + for (var i = 0; i < level.map.length; i++) { + if (level.map[i] === PORTAL) result.push(i); + } + return result; } function countSnakes() { - return getSnakes().length; + return getSnakes().length; } function getSnakes() { - return getObjectsOfType(SNAKE); + return getObjectsOfType(SNAKE); } function getBlocks() { - return getObjectsOfType(BLOCK); + return getObjectsOfType(BLOCK); } -function getOccupiedClosedLiftLocations() -{ - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === CLOSEDLIFT) { - if (findObjectAtLocation(i)) - result.push(i); +function getOccupiedClosedLiftLocations() { + var result = []; + for (var i = 0; i < level.map.length; i++) { + if (level.map[i] === CLOSEDLIFT) { + if (findObjectAtLocation(i)) + result.push(i); + } } - } - return result; + return result; } function getObjectsOfType(type) { - return level.objects.filter(function(object) { - return object.type == type; - }); + return level.objects.filter(function (object) { + return object.type == type; + }); } function isDead() { - if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; - return getSnakes().filter(function(snake) { - return !!snake.dead; - }).length > 0; + if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; + return getSnakes().filter(function (snake) { + return !!snake.dead; + }).length > 0; } function isAlive() { - return countSnakes() > 0 && !isDead(); + return countSnakes() > 0 && !isDead(); } var activeSnakeId = null; @@ -2334,22 +2329,22 @@ var DIE_SNAKE = "ds"; var DIE_BLOCK = "db"; var INFINITE_LOOP = "il"; var animationQueue = [ - // // sequence of disjoint animation groups. - // // each group completes before the next begins. - // [ - // 70, // duration of this animation group - // // multiple things to animate simultaneously - // [ - // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, - // objectId, - // dr, - // dc, - // ], - // [ - // INFINITE_LOOP, - // loopSizeNotIncludingThis, - // ], - // ], + // // sequence of disjoint animation groups. + // // each group completes before the next begins. + // [ + // 70, // duration of this animation group + // // multiple things to animate simultaneously + // [ + // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, + // objectId, + // dr, + // dc, + // ], + // [ + // INFINITE_LOOP, + // loopSizeNotIncludingThis, + // ], + // ], ]; var animationQueueCursor = 0; var animationStart = null; // new Date().getTime() @@ -2359,33 +2354,33 @@ var freshlyRemovedAnimatedObjects = []; // render the support beams for blocks into a temporary buffer, and remember it. // this is due to stencil buffers causing slowdown on some platforms. see #25. var blockSupportRenderCache = { - // id: canvas, - // "0": document.createElement("canvas"), + // id: canvas, + // "0": document.createElement("canvas"), }; function render() { - if (level == null) return; - if (animationQueueCursor < animationQueue.length) { - var animationDuration = animationQueue[animationQueueCursor][0]; - animationProgress = (new Date().getTime() - animationStart) / animationDuration; - if (animationProgress >= 1.0) { - // animation group complete - animationProgress -= 1.0; - animationQueueCursor++; - if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { - var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; - animationQueueCursor -= infiniteLoopSize; - } - animationStart = new Date().getTime(); + if (level == null) return; + if (animationQueueCursor < animationQueue.length) { + var animationDuration = animationQueue[animationQueueCursor][0]; + animationProgress = (new Date().getTime() - animationStart) / animationDuration; + if (animationProgress >= 1.0) { + // animation group complete + animationProgress -= 1.0; + animationQueueCursor++; + if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { + var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; + animationQueueCursor -= infiniteLoopSize; + } + animationStart = new Date().getTime(); + } } - } - if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; - canvas.width = tileSize * level.width; - canvas.height = tileSize * level.height; - var context = canvas.getContext("2d"); //Gooby - - themeName = themes[themeCounter][0]; - if(themeName!="sky"){ + if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; + canvas.width = tileSize * level.width; + canvas.height = tileSize * level.height; + var context = canvas.getContext("2d"); //Gooby + + themeName = themes[themeCounter][0]; + if (themeName != "sky") { background = themes[themeCounter][1]; material = themes[themeCounter][2]; surface = themes[themeCounter][3]; @@ -2396,786 +2391,806 @@ function render() { fruitColors = themes[themeCounter][8]; textStyle = themes[themeCounter][10]; experimentalColors = themes[themeCounter][11]; - - if(background.substr(0,1) == "#") { + + if (background.substr(0, 1) == "#") { context.fillStyle = background; context.fillRect(0, 0, canvas.width, canvas.height); } - else{ - for(var i = 0; i maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var image = blockSupportRenderCache[object.id]; - if (image == null) { - // render the support beams to a buffer - blockSupportRenderCache[object.id] = image = document.createElement("canvas"); - image.width = (maxC - minC + 1) * tileSize; - image.height = (maxR - minR + 1) * tileSize; - var bufferContext = image.getContext("2d"); - // Make a stencil that excludes the insides of blocks. - // Then when we render the support beams, we won't see the supports inside the block itself. - bufferContext.beginPath(); - // Draw a path around the whole screen in the opposite direction as the rectangle paths below. - // This means that the below rectangles will be removing area from the greater rectangle. - bufferContext.rect(image.width, 0, -image.width, image.height); - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r - minR; - var c = rowcol.c - minC; - bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); - } - bufferContext.clip(); - for (var i = 0; i < object.locations.length - 1; i++) { - var rowcol1 = getRowcol(level, object.locations[i]); - rowcol1.r -= minR; - rowcol1.c -= minC; - var rowcol2 = getRowcol(level, object.locations[i + 1]); - rowcol2.r -= minR; - rowcol2.c -= minC; - var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; - drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - } - } - var r = minR + animationDisplacementRowcol.r; - var c = minC + animationDisplacementRowcol.c; - context.drawImage(image, c * tileSize, r * tileSize); - }); - - if(!cs) { - // terrain - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - var tileCode = level.map[location]; - drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids + // active snake halo - Gooby + /*if (countSnakes() !== 0 && isAlive()) { + var activeSnake = findActiveSnake(); + var activeSnakeRowcol = getRowcol(level, activeSnake.locations[0]); + drawCircle(activeSnakeRowcol.r, activeSnakeRowcol.c, 2, "rgba(256,256,256,0.3)"); + }*/ + + if (persistentState.showEditor) { + if (paintBrushTileCode === BLOCK) { + if (paintBrushBlockId != null) { + // fade everything else away + context.fillStyle = "rgba(0, 0, 0, 0.8)"; + context.fillRect(0, 0, canvas.width, canvas.height); + // and render just this object in focus + var activeBlock = findBlockById(paintBrushBlockId); + renderLevel([activeBlock]); } - } + } else if (paintBrushTileCode === "select") { + getSelectedLocations().forEach(function (location) { + var rowcol = getRowcol(level, location); + drawRect(rowcol.r, rowcol.c, "rgba(128, 128, 128, 0.3)"); + }); } + } + + // serialize + if (!isDead()) { + var serialization = stringifyLevel(level); + document.getElementById("serializationTextarea").value = serialization; + var link = location.href.substring(0, location.href.length - location.hash.length); + link += "#level=" + compressSerialization(serialization); + document.getElementById("shareLinkTextbox").value = link; + } + + // throw this in there somewhere + document.getElementById("showGridButton").textContent = (persistentState.showGrid ? "Hide" : "Show") + " Grid"; - for(var i = 0; i maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var image = blockSupportRenderCache[object.id]; + if (image == null) { + // render the support beams to a buffer + blockSupportRenderCache[object.id] = image = document.createElement("canvas"); + image.width = (maxC - minC + 1) * tileSize; + image.height = (maxR - minR + 1) * tileSize; + var bufferContext = image.getContext("2d"); + // Make a stencil that excludes the insides of blocks. + // Then when we render the support beams, we won't see the supports inside the block itself. + bufferContext.beginPath(); + // Draw a path around the whole screen in the opposite direction as the rectangle paths below. + // This means that the below rectangles will be removing area from the greater rectangle. + bufferContext.rect(image.width, 0, -image.width, image.height); + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r - minR; + var c = rowcol.c - minC; + bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); + } + bufferContext.clip(); + for (var i = 0; i < object.locations.length - 1; i++) { + var rowcol1 = getRowcol(level, object.locations[i]); + rowcol1.r -= minR; + rowcol1.c -= minC; + var rowcol2 = getRowcol(level, object.locations[i + 1]); + rowcol2.r -= minR; + rowcol2.c -= minC; + var cornerRowcol = { r: rowcol1.r, c: rowcol2.c }; + drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); + drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); + } + } + var r = minR + animationDisplacementRowcol.r; + var c = minC + animationDisplacementRowcol.c; + context.drawImage(image, c * tileSize, r * tileSize); + }); - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - location = getLocation(level, r, c); - tileCode = level.map[location]; - if(tileCode === WALL) drawTile(tileCode, r, c, level, location, false); //draws only walls + if (!cs) { + // terrain + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + var tileCode = level.map[location]; + drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids + } + } } - } - } - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - location = getLocation(level, r, c); - tileCode = level.map[location]; - if(tileCode === CLOUD || tileCode === LAVA || tileCode === WATER) drawTile(tileCode, r, c, level, location, false); //draws only clouds + for (var i = 0; i < objects.length; i++) { + var object = objects[i]; + if (object.type === SNAKE || object.type === BLOCK) drawObject(object); //draws snakes and blocks } - } - } - for(var i = 0; i6) { color= color.substring(1,color.length)} - var rgb = parseInt(color, 16); - var r = Math.abs(((rgb >> 16) & 0xFF)+v); if (r>255) r=r-(r-255); - var g = Math.abs(((rgb >> 8) & 0xFF)+v); if (g>255) g=g-(g-255); - var b = Math.abs((rgb & 0xFF)+v); if (b>255) b=b-(b-255); - r = Number(r < 0 || isNaN(r)) ? 0 : ((r > 255) ? 255 : r).toString(16); - if (r.length == 1) r = '0' + r; - g = Number(g < 0 || isNaN(g)) ? 0 : ((g > 255) ? 255 : g).toString(16); - if (g.length == 1) g = '0' + g; - b = Number(b < 0 || isNaN(b)) ? 0 : ((b > 255) ? 255 : b).toString(16); - if (b.length == 1) b = '0' + b; - return "#" + r + g + b; -} - - function drawObject(object) { - switch (object.type) { - case SNAKE: - var falling = false; - var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); - if (animationDisplacementRowcol.r != 0) falling = true; - var lastRowcol = null - var nextRowcol = null - var color = snakeColors[object.id % snakeColors.length]; - var colorIndex = object.id % snakeColors.length; - var altColor = getTintedColor(color, 50); - if(themeName==="Classic") altColor = color; - var headRowcol; - var orientation = 10; - for (var i = 0; i < object.locations.length; i++) { - var animation; - var rowcol; - if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward - rowcol = getRowcol(level, object.locations[i]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else if (i === object.locations.length) { - // animated tail? - if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { - // animate tail slithering to catch up - rowcol = getRowcol(level, object.locations[i-1]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else { - // no animated tail needed - break; - } - } else rowcol = getRowcol(level, object.locations[i]); - - lastRowcol = getRowcol(level, object.locations[i-1]); //closer to head - nextRowcol = getRowcol(level, object.locations[i+1]); //closer to tail - var rc = rowcol; - var lrc = lastRowcol; - var nrc = nextRowcol; - - if (object.dead) { //if snake dies after moving left or right, head is positioned down - rowcol.r += .5; - lastRowcol.r += .5; - nextRowcol.r += .5; - falling = true; - } - rowcol.r += animationDisplacementRowcol.r; - rowcol.c += animationDisplacementRowcol.c; - lastRowcol.r += animationDisplacementRowcol.r; - lastRowcol.c += animationDisplacementRowcol.c; - nextRowcol.r += animationDisplacementRowcol.r; - nextRowcol.c += animationDisplacementRowcol.c; - - var cx = rowcol.c * tileSize; - var cy = rowcol.r * tileSize; - - if (i === 0) { - context.fillStyle = color; - headRowcol = rowcol; - - //determines orientation of face - if(!falling) nextRowcol = getRowcol(level, object.locations[1]); - if (nextRowcol.r < rowcol.r) { //last move down - roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false); //draw head - if(colorIndex === 0) orientation = 2; - else if(colorIndex === 1) orientation = 6; - else if(colorIndex === 2) orientation = 3; - else if(colorIndex === 3) orientation = 5; - } - else if (nextRowcol.r > rowcol.r) { //last move up - roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false); //draw head - if(colorIndex === 0) orientation = 0; - else if(colorIndex === 1) orientation = 4; - else if(colorIndex === 2) orientation = 1; - else if(colorIndex === 3) orientation = 7; - } - else if (nextRowcol.c < rowcol.c) { //last move right - roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false); //draw head - if(colorIndex === 0) orientation = 1; - else if(colorIndex === 1) orientation = 5; - else if(colorIndex === 2) orientation = 2; - else if(colorIndex === 3) orientation = 4; - } - else if (nextRowcol.c > rowcol.c) { //last move left - roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false); //draw head - if(colorIndex === 0) orientation = 3; - else if(colorIndex === 1) orientation = 7; - else if(colorIndex === 2) orientation = 0; - else if(colorIndex === 3) orientation = 6; + + function lighten(hex) { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + + var r = parseInt(result[1], 16); + var g = parseInt(result[2], 16); + var b = parseInt(result[3], 16); + + r /= 255, g /= 255, b /= 255; + var max = Math.max(r, g, b), min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if (max == min) { + h = s = 0; // achromatic + } else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch (max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; } - else { - roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); //draw head - orientation = 10; - } - } else { - if(i % 2 == 0) context.fillStyle = color; - else context.fillStyle = altColor; - - if (i === object.locations.length-1) { - if(lastRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false);} - else if(lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false);} - else if(lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false);} - else if(lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false);} + h /= 6; + } + + s = s * 100; + s = Math.round(s); + l = l * 100 * 1.2; + l = Math.round(l); + h = Math.round(360*h); + + return 'hsl(' + h + ', ' + s + '%, ' + l + '%)'; + } + + function drawObject(object) { + switch (object.type) { + case SNAKE: + var falling = false; + var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); + if (animationDisplacementRowcol.r != 0) falling = true; + var lastRowcol = null + var nextRowcol = null + var color = snakeColors[object.id % snakeColors.length]; + var colorIndex = object.id % snakeColors.length; + //var altColor = getTintedColor(color, 30); + var altColor = lighten(color); + if (themeName === "Classic") altColor = color; + var headRowcol; + var orientation = 10; + for (var i = 0; i < object.locations.length; i++) { + var animation; + var rowcol; + if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward + rowcol = getRowcol(level, object.locations[i]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else if (i === object.locations.length) { + // animated tail? + if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { + // animate tail slithering to catch up + rowcol = getRowcol(level, object.locations[i - 1]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else { + // no animated tail needed + break; + } + } else rowcol = getRowcol(level, object.locations[i]); + + lastRowcol = getRowcol(level, object.locations[i - 1]); //closer to head + nextRowcol = getRowcol(level, object.locations[i + 1]); //closer to tail + var rc = rowcol; + var lrc = lastRowcol; + var nrc = nextRowcol; + + if (object.dead) { //if snake dies after moving left or right, head is positioned down + rowcol.r += .5; + lastRowcol.r += .5; + nextRowcol.r += .5; + falling = true; + } + rowcol.r += animationDisplacementRowcol.r; + rowcol.c += animationDisplacementRowcol.c; + lastRowcol.r += animationDisplacementRowcol.r; + lastRowcol.c += animationDisplacementRowcol.c; + nextRowcol.r += animationDisplacementRowcol.r; + nextRowcol.c += animationDisplacementRowcol.c; + + var cx = rowcol.c * tileSize; + var cy = rowcol.r * tileSize; + + if (i === 0) { + context.fillStyle = color; + headRowcol = rowcol; + + //determines orientation of face + if (!falling) nextRowcol = getRowcol(level, object.locations[1]); + if (nextRowcol.r < rowcol.r) { //last move down + roundRect(context, cx, cy, tileSize, tileSize, { bl: 10, br: 10 }, true, false); //draw head + if (colorIndex === 0) orientation = 2; + else if (colorIndex === 1) orientation = 6; + else if (colorIndex === 2) orientation = 3; + else if (colorIndex === 3) orientation = 5; + } + else if (nextRowcol.r > rowcol.r) { //last move up + roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); //draw head + if (colorIndex === 0) orientation = 0; + else if (colorIndex === 1) orientation = 4; + else if (colorIndex === 2) orientation = 1; + else if (colorIndex === 3) orientation = 7; + } + else if (nextRowcol.c < rowcol.c) { //last move right + roundRect(context, cx, cy, tileSize, tileSize, { tr: 10, br: 10 }, true, false); //draw head + if (colorIndex === 0) orientation = 1; + else if (colorIndex === 1) orientation = 5; + else if (colorIndex === 2) orientation = 2; + else if (colorIndex === 3) orientation = 4; + } + else if (nextRowcol.c > rowcol.c) { //last move left + roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); //draw head + if (colorIndex === 0) orientation = 3; + else if (colorIndex === 1) orientation = 7; + else if (colorIndex === 2) orientation = 0; + else if (colorIndex === 3) orientation = 6; + } + else { + roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); //draw head + orientation = 10; + } + } else { + if (i % 2 == 0) context.fillStyle = color; + else context.fillStyle = altColor; + + if (i === object.locations.length - 1) { + if (lastRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); } + else if (lastRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10, br: 10 }, true, false); } + else if (lastRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10, br: 10 }, true, false); } + else if (lastRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); } + } + else if (i != object.locations.length - 1 && i != object.locations.length) { + if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10 }, true, false); } + else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10 }, true, false); } + else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { br: 10 }, true, false); } + else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10 }, true, false); } + + else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10 }, true, false); } + else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10 }, true, false); } + else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { br: 10 }, true, false); } + else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10 }, true, false); } + + else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, 0, true, false); } + } + else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); + } } - else if (i != object.locations.length-1 && i != object.locations.length) { - if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} - else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} - else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} - else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} - - else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} - else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} - else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} - else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} - - else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, 0, true, false);} + drawFace(object.id, headRowcol.c, headRowcol.r, orientation); + break; + case BLOCK: + drawBlock(object); + break; + case FRUIT: + case POISON_FRUIT: + var is_poison = object.type == POISON_FRUIT; + rowcol = getRowcol(level, object.locations[0]); + var c = rowcol.c; + var r = rowcol.r; + var startC = c * tileSize + tileSize / 2; + var startR = r * tileSize + tileSize * .2; + var resize = tileSize * 1.7; + var color = fruitColors[object.id % fruitColors.length]; + var stemColor = themes[themeCounter][9] + if (themeName === "Classic") color = "#f0f"; + if (is_poison) { color = "#556815"; stemColor = "black"; } + context.fillStyle = color; + if (themeName != "Classic") { + if (surface == "rainbow") { + context.fillStyle = "black"; + context.lineWidth = tileSize / 8; + context.strokeStyle = "white"; + resize = tileSize * 1.4; + } + //context.fillStyle = "#ff6b45"; + context.beginPath(); + context.moveTo(startC, startR); + context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC - resize * .25, startR - resize * .1, startC - resize * .3, startR + resize * .05); + context.bezierCurveTo(startC - resize * .35, startR + resize * .15, startC - resize * .3, startR + resize * .6, startC, startR + resize * .5); + context.bezierCurveTo(startC + resize * .3, startR + resize * .6, startC + resize * .35, startR + resize * .15, startC + resize * .3, startR + resize * .05); + context.bezierCurveTo(startC + resize * .25, startR - resize * .05, startC + resize * .1, startR - resize * .1, startC, startR); + context.closePath(); + context.fill(); + if (surface == "rainbow") context.stroke(); + + context.beginPath(); + context.moveTo(startC, startR); + context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC, startR - resize * .1, startC - resize * .1, startR - resize * .15); + context.bezierCurveTo(startC, startR - resize * .1, startC + resize * .05, startR - resize * .1, startC, startR); + context.fillStyle = stemColor; + context.fill(); } - else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); - } + else drawCircle(rowcol.r, rowcol.c, 1, color); + break; + default: throw unreachable(); } - drawFace(object.id, headRowcol.c, headRowcol.r, orientation); - break; - case BLOCK: - drawBlock(object); - break; - case FRUIT: - case POISON_FRUIT: - var is_poison = object.type == POISON_FRUIT; - rowcol = getRowcol(level, object.locations[0]); - var c = rowcol.c; - var r = rowcol.r; - var startC = c*tileSize+tileSize/2; - var startR = r*tileSize+tileSize*.2; - var resize = tileSize * 1.7; - var color = fruitColors[object.id % fruitColors.length]; - var stemColor = themes[themeCounter][9] - if (is_poison) { color = "#556815"; stemColor = "black";} //placeholder effect - context.fillStyle = color; - if(themeName != "Classic"){ - if(surface == "rainbow") { - context.fillStyle = "black"; - context.lineWidth = tileSize/8; - context.strokeStyle = "white"; - resize = tileSize * 1.4; - } - //context.fillStyle = "#ff6b45"; - context.beginPath(); - context.moveTo(startC, startR); - context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC-resize*.25, startR-resize*.1, startC-resize*.3, startR+resize*.05); - context.bezierCurveTo(startC-resize*.35, startR+resize*.15, startC-resize*.3, startR+resize*.6, startC, startR+resize*.5); - context.bezierCurveTo(startC+resize*.3, startR+resize*.6, startC+resize*.35, startR+resize*.15, startC+resize*.3, startR+resize*.05); - context.bezierCurveTo(startC+resize*.25, startR-resize*.05, startC+resize*.1, startR-resize*.1, startC, startR); - context.closePath(); - context.fill(); - if(surface == "rainbow") context.stroke(); + } - context.beginPath(); - context.moveTo(startC,startR); - context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); - context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); - context.fillStyle = stemColor; - context.fill(); + function drawPlatform(r, c, adjacentTiles) { + newPlatform(r, c, isPlatform); + + function isPlatform(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === PLATFORM; } - else drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); - break; - default: throw unreachable(); + + /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*1, r*tileSize); + context.lineTo(c*tileSize, r*tileSize); + context.closePath(); + context.rect(c*tileSize, r*tileSize+tileSize*.2857, tileSize, tileSize*.1429);*/ + + /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.25, r*tileSize+tileSize*.2, c*tileSize+tileSize*.25, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.75, r*tileSize+tileSize*.2, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.lineTo((c+1)*tileSize, r*tileSize); + context.lineTo(c*tileSize, r*tileSize);*/ + + /*context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.arc((c + 3/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.arc((c + 1/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.lineTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize+tileSize, r*tileSize);*/ + + //context.closePath(); + //context.fillStyle = "#000066"; + //ontext.fill(); + //context.stroke(); } - } - -function drawPlatform(r, c, adjacentTiles) { - newPlatform(r, c, isPlatform); - - function isPlatform(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === PLATFORM; + + function newPlatform(r, c, isOccupied) { + + var x1 = .05; + var x2 = .05; + if (isOccupied(-1, 0)) x1 = 0; + if (isOccupied(1, 0)) x2 = 0; + + var platformColors = ["#ffcccc", "#ffe0cc", "#ffffcc", "#e6ffe6", "#e6e6ff"]; + for (var i = 0; i < 5; i++) { + var j = i - 1; + if (j < 0) j = 0; + context.beginPath(); + context.moveTo(c * tileSize + tileSize * (i * x1), r * tileSize + tileSize * (.05 + (.1 * i) - (j * .02))); + context.strokeStyle = platformColors[i]; + context.lineWidth = tileSize * (.1 - (i * .02)); + context.lineTo(c * tileSize + tileSize * (1 - (i * x2)), r * tileSize + tileSize * (.05 + (.1 * i) - (j * .02))); + context.stroke(); + } } - - /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*1, r*tileSize); - context.lineTo(c*tileSize, r*tileSize); - context.closePath(); - context.rect(c*tileSize, r*tileSize+tileSize*.2857, tileSize, tileSize*.1429);*/ - - /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.25, r*tileSize+tileSize*.2, c*tileSize+tileSize*.25, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.75, r*tileSize+tileSize*.2, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo((c+1)*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize);*/ - - /*context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.arc((c + 3/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.arc((c + 1/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.lineTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize, r*tileSize);*/ - - //context.closePath(); - //context.fillStyle = "#000066"; - //ontext.fill(); - //context.stroke(); -} - -function newPlatform(r, c, isOccupied){ - - var x1 = .05; - var x2 = .05; - if(isOccupied(-1,0)) x1 = 0; - if(isOccupied(1,0)) x2 = 0; - - var platformColors = ["#ffcccc", "#ffe0cc", "#ffffcc", "#e6ffe6", "#e6e6ff"]; - for(var i = 0; i<5; i++){ - var j = i-1; - if(j<0) j = 0; + + function drawOneWayWall(fillStyle, r, c, dr, dc) { + context.lineWidth = 2; + context.strokeStyle = "#333"; context.beginPath(); - context.moveTo(c*tileSize+tileSize*(i*x1), r*tileSize+tileSize*(.05 + (.1 * i) - (j * .02))); - context.strokeStyle = platformColors[i]; - context.lineWidth = tileSize*(.1-(i*.02)); - context.lineTo(c*tileSize+tileSize*(1-(i*x2)), r*tileSize+tileSize*(.05 + (.1 * i) - (j * .02))); + + if (dr == -1) { + context.moveTo(c * tileSize, r * tileSize + tileSize / 2); + context.lineTo(c * tileSize + tileSize / 4, r * tileSize + tileSize / 4); + context.stroke(); + context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + tileSize / 4); + context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize / 2); + } + else if (dr == 1) { + context.moveTo(c * tileSize, r * tileSize + tileSize / 2); + context.lineTo(c * tileSize + tileSize / 4, r * tileSize + 3 * tileSize / 4); + context.stroke(); + context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + 3 * tileSize / 4); + context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize / 2); + } + else if (dc == -1) { + context.moveTo(c * tileSize + tileSize / 2, r * tileSize); + context.lineTo(c * tileSize + tileSize / 4, r * tileSize + tileSize / 4); + context.stroke(); + context.moveTo(c * tileSize + tileSize / 4, r * tileSize + 3 * tileSize / 4); + context.lineTo(c * tileSize + tileSize / 2, r * tileSize + tileSize); + } + else if (dc == 1) { + context.moveTo(c * tileSize + tileSize / 2, r * tileSize); + context.lineTo(c * tileSize + 3 * tileSize / 4, r * tileSize + tileSize / 4); + context.stroke(); + context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + 3 * tileSize / 4); + context.lineTo(c * tileSize + tileSize / 2, r * tileSize + tileSize); + } + context.stroke(); + context.lineWidth = 0; + + context.fillStyle = fillStyle; + if (dr == -1) roundRect(context, c * tileSize - tileSize / 15, r * tileSize - tileSize / 15, tileSize + 2 * tileSize / 15, tileSize / 4 + 2 * tileSize / 15, 2, true, false); + else if (dr == 1) roundRect(context, c * tileSize - tileSize / 15, (r + 1) * tileSize - tileSize / 15 - tileSize / 4, tileSize + 2 * tileSize / 15, tileSize / 4 + 2 * tileSize / 15, 2, true, false); + else if (dc == -1) roundRect(context, c * tileSize - tileSize / 15, r * tileSize - tileSize / 15, tileSize / 4 + 2 * tileSize / 15, tileSize + 2 * tileSize / 15, 2, true, false); + else if (dc == 1) roundRect(context, (c + 1) * tileSize - tileSize / 15 - tileSize / 4, r * tileSize - tileSize / 15, tileSize / 4 + 2 * tileSize / 15, tileSize + 2 * tileSize / 15, 2, true, false); } -} - - function drawOneWayWall(fillStyle, r, c, dr, dc) { - context.lineWidth = 2; - context.strokeStyle = "#333"; - context.beginPath(); - - if (dr == -1) { - context.moveTo(c * tileSize, r * tileSize + tileSize/2); - context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); - context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); - } - else if (dr == 1) { - context.moveTo(c * tileSize, r * tileSize + tileSize/2); - context.lineTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); - context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); - } - else if (dc == -1) { - context.moveTo(c * tileSize + tileSize/2, r * tileSize); - context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); - context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); - } - else if (dc == 1) { - context.moveTo(c * tileSize + tileSize/2, r * tileSize); - context.lineTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); - context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); - } - - context.stroke(); - context.lineWidth = 0; - - context.fillStyle = fillStyle; - if (dr == -1) roundRect(context, c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15, 2, true, false); - else if (dr == 1) roundRect(context, c * tileSize - tileSize/15, (r + 1) * tileSize - tileSize/15 - tileSize/4, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15, 2, true, false); - else if (dc == -1) roundRect(context, c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15, 2, true, false); - else if (dc == 1) roundRect(context, (c + 1) * tileSize - tileSize/15 - tileSize/4, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15, 2, true, false); - } - - function drawBubble(r, c) { - bubbleX = c*tileSize; - var grd = context.createRadialGradient(bubbleX, r*tileSize, 0, bubbleX, r*tileSize, tileSize); - grd.addColorStop(0, "rgba(255,255,255,.9)"); - grd.addColorStop(1, "rgba(255,255,255,.2)"); - context.fillStyle = grd; - context.lineWidth = .5; - context.strokeStyle = "rgba(200,200,200,.2)"; - - context.beginPath(); - context.arc(c*tileSize+tileSize*.5, r*tileSize+tileSize*.5, tileSize/2, 0, 2*Math.PI); - context.fill(); - context.stroke(); - } - -function drawLiquid(r, c, type, adjacentTiles) { - newLiquid(r, c, type, isSameLiquid); - - function isSameLiquid(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === type; - } -} - -function newLiquid(r, c, type, isOccupied){ - context.save(); - var tubColor; - if(type == LAVA) { - context.fillStyle = "#ffbf00"; - context.strokeStyle = "red"; - tubColor = "black"; - } - else { - context.fillStyle = "#1a8cff"; - context.strokeStyle = "#80ffe5"; - tubColor = "white"; + + function drawBubble(r, c) { + bubbleX = c * tileSize; + var grd = context.createRadialGradient(bubbleX, r * tileSize, 0, bubbleX, r * tileSize, tileSize); + grd.addColorStop(0, "rgba(255,255,255,.9)"); + grd.addColorStop(1, "rgba(255,255,255,.2)"); + context.fillStyle = grd; + context.lineWidth = .5; + context.strokeStyle = "rgba(200,200,200,.2)"; + + context.beginPath(); + context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, tileSize / 2, 0, 2 * Math.PI); + context.fill(); + context.stroke(); } - roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); - - context.lineWidth = 3; - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.1, c*tileSize+tileSize/3, r*tileSize+tileSize*.1, c*tileSize+tileSize/2, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.3, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.3, c*tileSize+tileSize, r*tileSize+tileSize*.2); - context.moveTo(c*tileSize, r*tileSize+tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.3, c*tileSize+tileSize/3, r*tileSize+tileSize*.3, c*tileSize+tileSize/2, r*tileSize+tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.5, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.5, c*tileSize+tileSize, r*tileSize+tileSize*.4); - context.moveTo(c*tileSize, r*tileSize+tileSize*.6); - context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.5, c*tileSize+tileSize/3, r*tileSize+tileSize*.5, c*tileSize+tileSize/2, r*tileSize+tileSize*.6); - context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.7, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.7, c*tileSize+tileSize, r*tileSize+tileSize*.6); - context.moveTo(c*tileSize, r*tileSize+tileSize*.8); - context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.7, c*tileSize+tileSize/3, r*tileSize+tileSize*.7, c*tileSize+tileSize/2, r*tileSize+tileSize*.8); - context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.9, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.9, c*tileSize+tileSize, r*tileSize+tileSize*.8); - context.stroke(); - - context.fillStyle = tubColor; - if(!isOccupied(-1,0)) { - if(isOccupied(-1,-1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize-tileSize*.2, tileSize*.2, tileSize*1.2, 0, true, false); - else roundRect(context, c*tileSize-tileSize*.1, r*tileSize, tileSize*.2, tileSize, 0, true, false); + + function drawLiquid(r, c, type, adjacentTiles) { + newLiquid(r, c, type, isSameLiquid); + + function isSameLiquid(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === type; + } } - if(!isOccupied(1,0)) roundRect(context, c*tileSize+tileSize*.9, r*tileSize, tileSize*.2, tileSize, 0, true, false); - if(!isOccupied(0,1)) { - if(isOccupied(-1,1) && !isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); - else if(!isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize*1.3, tileSize*.2, 0, true, false); - else if(isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); - else roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize, tileSize*.2, 0, true, false); + + function newLiquid(r, c, type, isOccupied) { + context.save(); + var tubColor; + if (type == LAVA) { + context.fillStyle = "#ffbf00"; + context.strokeStyle = "red"; + tubColor = "black"; + } + else { + context.fillStyle = "#1a8cff"; + context.strokeStyle = "#80ffe5"; + tubColor = "white"; + } + roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 0, true, false); + + context.lineWidth = 3; + context.beginPath(); + context.moveTo(c * tileSize, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .1, c * tileSize + tileSize / 3, r * tileSize + tileSize * .1, c * tileSize + tileSize / 2, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .3, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .3, c * tileSize + tileSize, r * tileSize + tileSize * .2); + context.moveTo(c * tileSize, r * tileSize + tileSize * .4); + context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .3, c * tileSize + tileSize / 3, r * tileSize + tileSize * .3, c * tileSize + tileSize / 2, r * tileSize + tileSize * .4); + context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .5, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .5, c * tileSize + tileSize, r * tileSize + tileSize * .4); + context.moveTo(c * tileSize, r * tileSize + tileSize * .6); + context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .5, c * tileSize + tileSize / 3, r * tileSize + tileSize * .5, c * tileSize + tileSize / 2, r * tileSize + tileSize * .6); + context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .7, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .7, c * tileSize + tileSize, r * tileSize + tileSize * .6); + context.moveTo(c * tileSize, r * tileSize + tileSize * .8); + context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .7, c * tileSize + tileSize / 3, r * tileSize + tileSize * .7, c * tileSize + tileSize / 2, r * tileSize + tileSize * .8); + context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .9, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .9, c * tileSize + tileSize, r * tileSize + tileSize * .8); + context.stroke(); + + context.fillStyle = tubColor; + if (!isOccupied(-1, 0)) { + if (isOccupied(-1, -1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize - tileSize * .2, tileSize * .2, tileSize * 1.2, 0, true, false); + else roundRect(context, c * tileSize - tileSize * .1, r * tileSize, tileSize * .2, tileSize, 0, true, false); + } + if (!isOccupied(1, 0)) roundRect(context, c * tileSize + tileSize * .9, r * tileSize, tileSize * .2, tileSize, 0, true, false); + if (!isOccupied(0, 1)) { + if (isOccupied(-1, 1) && !isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize + tileSize * .8, tileSize * 1.1, tileSize * .2, 0, true, false); + else if (!isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize, r * tileSize + tileSize * .8, tileSize * 1.3, tileSize * .2, 0, true, false); + else if (isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize + tileSize * .8, tileSize * 1.1, tileSize * .2, 0, true, false); + else roundRect(context, c * tileSize, r * tileSize + tileSize * .8, tileSize, tileSize * .2, 0, true, false); + } + context.restore(); } - context.restore(); -} - function drawLift(r, c, isFixed) { + function drawLift(r, c, isFixed) { context.lineWidth = .5; context.strokeStyle = "#777"; var strokeBool = false; - if(!isFixed) { + if (!isFixed) { context.fillStyle = "#e68a00"; - roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); + roundRect(context, c * tileSize + tileSize * .05, r * tileSize + tileSize, tileSize * .9, tileSize * .2, 2, true, strokeBool); context.fillStyle = "#cc0000"; - roundRect(context, c*tileSize+tileSize*.3, r*tileSize+tileSize*.8, tileSize*.4, tileSize*.2, {tl:2, tr:2}, true, strokeBool); + roundRect(context, c * tileSize + tileSize * .3, r * tileSize + tileSize * .8, tileSize * .4, tileSize * .2, { tl: 2, tr: 2 }, true, strokeBool); } - else if(isFixed) { + else if (isFixed) { context.fillStyle = "#e68a00"; - roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize*.8, tileSize*.9, tileSize*.2, 2, true, strokeBool); - roundRect(context, c*tileSize+tileSize*.05, r*tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); - + roundRect(context, c * tileSize + tileSize * .05, r * tileSize + tileSize * .8, tileSize * .9, tileSize * .2, 2, true, strokeBool); + roundRect(context, c * tileSize + tileSize * .05, r * tileSize, tileSize * .9, tileSize * .2, 2, true, strokeBool); + context.fillStyle = "#333"; - + context.beginPath(); - context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.45); - context.bezierCurveTo(c*tileSize+tileSize*.16,r*tileSize+tileSize*.45,c*tileSize+tileSize*.16,r*tileSize+tileSize*.55,c*tileSize+tileSize*.2,r*tileSize+tileSize*.55); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); + context.moveTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .8); + context.lineTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .5); + context.lineTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize * .7, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize * .2, r * tileSize + tileSize * .45); + context.bezierCurveTo(c * tileSize + tileSize * .16, r * tileSize + tileSize * .45, c * tileSize + tileSize * .16, r * tileSize + tileSize * .55, c * tileSize + tileSize * .2, r * tileSize + tileSize * .55); + context.lineTo(c * tileSize + tileSize * .7, r * tileSize + tileSize * .8); + context.lineTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .8); context.closePath(); context.fill(); - + context.beginPath(); - context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.45); - context.bezierCurveTo(c*tileSize+tileSize*.84,r*tileSize+tileSize*.45,c*tileSize+tileSize*.84,r*tileSize+tileSize*.55,c*tileSize+tileSize*.8,r*tileSize+tileSize*.55); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.8); + context.moveTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .8); + context.lineTo(c * tileSize + tileSize * .7, r * tileSize + tileSize * .5); + context.lineTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize * .8, r * tileSize + tileSize * .45); + context.bezierCurveTo(c * tileSize + tileSize * .84, r * tileSize + tileSize * .45, c * tileSize + tileSize * .84, r * tileSize + tileSize * .55, c * tileSize + tileSize * .8, r * tileSize + tileSize * .55); + context.lineTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .8); + context.lineTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .8); context.closePath(); context.fill(); - + /*context.beginPath(); context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.9); context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); @@ -3198,7 +3213,7 @@ function newLiquid(r, c, type, isOccupied){ context.closePath(); context.fill();*/ } - + /*var grd = context.createLinearGradient(c*tileSize, r*tileSize, (c+1)*tileSize, (r+1)*tileSize); grd.addColorStop(0, "rgba(255,255,255,.6)"); grd.addColorStop(.1, "rgba(255,255,255,.7)"); @@ -3304,37 +3319,37 @@ function newLiquid(r, c, type, isOccupied){ context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.2); context.stroke(); }*/ - } - - function drawWall(r, c, adjacentTiles) { //GOOBY - //drawRect(r, c, "#976537"); - drawTileNew(r, c, isWall, 0.2, material); - drawTileOutlines(r, c, isWall, 0.2, curlyOutline); - context.save(); - if(curlyOutline) drawBushes(r, c, isWall); - context.restore(); - context.fillStyle = "#895C33"; // dirt edge - //drawTileOutlines(r, c, isWall, 0.2, false); - - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; } - } - - function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle){ + + function drawWall(r, c, adjacentTiles) { //GOOBY + //drawRect(r, c, "#976537"); + drawTileNew(r, c, isWall, 0.2, material); + drawTileOutlines(r, c, isWall, 0.2, curlyOutline); + context.save(); + if (curlyOutline) drawBushes(r, c, isWall); + context.restore(); + context.fillStyle = "#895C33"; // dirt edge + //drawTileOutlines(r, c, isWall, 0.2, false); + + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } + } + + function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle) { context.fillStyle = fillStyle; - if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10,br:10}, true, false); - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10}, true, false); - else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {br:10}, true, false); - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); - else roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); - + if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { bl: 10, br: 10 }, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tr: 10, br: 10 }, true, false); + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { bl: 10 }, true, false); + else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { br: 10 }, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tl: 10 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tr: 10 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 10, true, false); + else roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 0, true, false); + /*var randomSpot = Math.floor(Math.random() * 5); //random spots on dirt var randomColor = Math.floor(Math.random() * 5); context.beginPath(); @@ -3352,1062 +3367,1063 @@ function newLiquid(r, c, type, isOccupied){ } context.stroke();*/ } - - function drawCurves(r, c, adjacentTiles){ + + function drawCurves(r, c, adjacentTiles) { drawCurves2(r, c, isWall, material); - + function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; } } - - function drawCurves2(r, c, isOccupied, material){ + + function drawCurves2(r, c, isOccupied, material) { context.fillStyle = material; - if(isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { - context.fillRect((c+1)*tileSize, (r+1)*tileSize, tileSize/6, tileSize/6); + if (isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { + context.fillRect((c + 1) * tileSize, (r + 1) * tileSize, tileSize / 6, tileSize / 6); //context.globalCompositeOperation = "destination-out"; context.beginPath(); - context.arc((c+1)*tileSize+tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); + context.arc((c + 1) * tileSize + tileSize / 6, (r + 1) * tileSize + tileSize / 6, tileSize / 6, 0, 2 * Math.PI); context.closePath(); - + var bgColor; - if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*')+2, background.length); + if ((c + r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*') + 2, background.length); var r1, r2, b1, b2, g1, g2; - r1 = bgColor.substr(5, bgColor.indexOf(",")-5); - g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); - b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); - var shade = (r+1)*.03+.5; - if(shade>1) + r1 = bgColor.substr(5, bgColor.indexOf(",") - 5); + g1 = bgColor.substr(bgColor.indexOf(",") + 1, bgColor.indexOf(",") - 4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",") + 1) + 1, bgColor.indexOf(",") - 4); + var shade = (r + 1) * .03 + .5; + if (shade > 1) shade = 1; - r2 = 255 + (r1-255) * shade; - g2 = 255 + (g1-255) * shade; - b2 = 255 + (b1-255) * shade; + r2 = 255 + (r1 - 255) * shade; + g2 = 255 + (g1 - 255) * shade; + b2 = 255 + (b1 - 255) * shade; context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; context.fill(); - context.globalCompositeOperation = "source-over"; + context.globalCompositeOperation = "source-over"; } - if(isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1) && curlyOutline) { - context.fillRect(c*tileSize-tileSize/6, (r+1)*tileSize, tileSize/6, tileSize/6); + if (isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1) && curlyOutline) { + context.fillRect(c * tileSize - tileSize / 6, (r + 1) * tileSize, tileSize / 6, tileSize / 6); //context.globalCompositeOperation = "destination-out"; context.beginPath(); - context.arc(c*tileSize-tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); + context.arc(c * tileSize - tileSize / 6, (r + 1) * tileSize + tileSize / 6, tileSize / 6, 0, 2 * Math.PI); context.closePath(); - + var bgColor; - if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*')+2, background.length); + if ((c + r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*') + 2, background.length); var r1, r2, b1, b2, g1, g2; - r1 = bgColor.substr(5, bgColor.indexOf(",")-5); - g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); - b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); - var shade = (r+1)*.03+.5; - if(shade>1) + r1 = bgColor.substr(5, bgColor.indexOf(",") - 5); + g1 = bgColor.substr(bgColor.indexOf(",") + 1, bgColor.indexOf(",") - 4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",") + 1) + 1, bgColor.indexOf(",") - 4); + var shade = (r + 1) * .03 + .5; + if (shade > 1) shade = 1; - r2 = 255 + (r1-255) * shade; - g2 = 255 + (g1-255) * shade; - b2 = 255 + (b1-255) * shade; + r2 = 255 + (r1 - 255) * shade; + g2 = 255 + (g1 - 255) * shade; + b2 = 255 + (b1 - 255) * shade; context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; context.fill(); context.globalCompositeOperation = "source-over"; } } - - function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { //Gooby - if(surface != "rainbow") { - context.fillStyle = surface; - } - else{ - context.fillStyle = "white"; - var mod = (r+c) % 17; - switch(mod){ - case 0: context.fillStyle = "#ff004c"; break; - case 1: context.fillStyle = "#e30000"; break; - case 2: context.fillStyle = "#ff4c00"; break; - case 3: context.fillStyle = "#ff9900"; break; - case 4: context.fillStyle = "#ffe500"; break; - case 5: context.fillStyle = "#cbff00"; break; - case 6: context.fillStyle = "#7fff00"; break; - case 7: context.fillStyle = "#00ff19"; break; - case 8: context.fillStyle = "#00ff66"; break; - case 9: context.fillStyle = "#00ffb2"; break; - case 10: context.fillStyle = "#00ffff"; break; - case 11: context.fillStyle = "#00b2ff"; break; - case 12: context.fillStyle = "#3200ff"; break; - case 13: context.fillStyle = "#5702c6"; break; - case 14: context.fillStyle = "#cc00ff"; break; - case 15: context.fillStyle = "#ff00e5"; break; - case 16: context.fillStyle = "#ff0098"; break; - } - } - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - var complementPixels = (1 - 2 * outlineThickness) * tileSize; - - if (curlyOutline && !isOccupied(0, -1)){ - if(!isOccupied(-1, 0) && isOccupied(1, 0)){ - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.4, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize); - context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); - context.closePath(); + + function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { //Gooby + if (surface != "rainbow") { + context.fillStyle = surface; } - else if(isOccupied(-1, 0) && !isOccupied(1, 0)){ - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.95, r*tileSize+tileSize*.3, c*tileSize+tileSize*.7, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.65, r*tileSize+tileSize*.4, c*tileSize+tileSize*.4, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.1, r*tileSize+tileSize*.4, c*tileSize, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize); - context.bezierCurveTo((c+1)*tileSize+tileSize*.2, r*tileSize-tileSize*.05, (c+1)*tileSize+tileSize*.15, r*tileSize+tileSize*.5, (c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.25); - context.closePath(); + else { + context.fillStyle = "white"; + var mod = (r + c) % 17; + switch (mod) { + case 0: context.fillStyle = "#ff004c"; break; + case 1: context.fillStyle = "#e30000"; break; + case 2: context.fillStyle = "#ff4c00"; break; + case 3: context.fillStyle = "#ff9900"; break; + case 4: context.fillStyle = "#ffe500"; break; + case 5: context.fillStyle = "#cbff00"; break; + case 6: context.fillStyle = "#7fff00"; break; + case 7: context.fillStyle = "#00ff19"; break; + case 8: context.fillStyle = "#00ff66"; break; + case 9: context.fillStyle = "#00ffb2"; break; + case 10: context.fillStyle = "#00ffff"; break; + case 11: context.fillStyle = "#00b2ff"; break; + case 12: context.fillStyle = "#3200ff"; break; + case 13: context.fillStyle = "#5702c6"; break; + case 14: context.fillStyle = "#cc00ff"; break; + case 15: context.fillStyle = "#ff00e5"; break; + case 16: context.fillStyle = "#ff0098"; break; + } } - else if(!isOccupied(-1, 0) && !isOccupied(1, 0)){ - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.9, r*tileSize-tileSize*0); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize); - context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); - context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.8, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); - context.bezierCurveTo((c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.4, (c+1)*tileSize+tileSize*.3, r*tileSize+tileSize*.3, (c+1)*tileSize, r*tileSize+tileSize*.02); - context.closePath(); + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + var complementPixels = (1 - 2 * outlineThickness) * tileSize; + + if (curlyOutline && !isOccupied(0, -1)) { + if (!isOccupied(-1, 0) && isOccupied(1, 0)) { + context.beginPath(); + context.moveTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .05, r * tileSize + tileSize * .3, c * tileSize + tileSize * .3, r * tileSize + tileSize * .4, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .35, r * tileSize + tileSize * .4, c * tileSize + tileSize * .6, r * tileSize + tileSize * .4, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .75, r * tileSize + tileSize * .3, c * tileSize + tileSize * .9, r * tileSize + tileSize * .4, c * tileSize + tileSize * 1, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize, r * tileSize); + context.lineTo(c * tileSize + tileSize * .2, r * tileSize); + context.bezierCurveTo(c * tileSize - tileSize * .2, r * tileSize - tileSize * .05, c * tileSize - tileSize * .15, r * tileSize + tileSize * .5, c * tileSize + tileSize * .1, r * tileSize + tileSize * .25); + context.closePath(); + } + else if (isOccupied(-1, 0) && !isOccupied(1, 0)) { + context.beginPath(); + context.moveTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .95, r * tileSize + tileSize * .3, c * tileSize + tileSize * .7, r * tileSize + tileSize * .4, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .65, r * tileSize + tileSize * .4, c * tileSize + tileSize * .4, r * tileSize + tileSize * .4, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .3, c * tileSize + tileSize * .1, r * tileSize + tileSize * .4, c * tileSize, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize, r * tileSize); + context.lineTo(c * tileSize + tileSize * .8, r * tileSize); + context.bezierCurveTo((c + 1) * tileSize + tileSize * .2, r * tileSize - tileSize * .05, (c + 1) * tileSize + tileSize * .15, r * tileSize + tileSize * .5, (c + 1) * tileSize - tileSize * .1, r * tileSize + tileSize * .25); + context.closePath(); + } + else if (!isOccupied(-1, 0) && !isOccupied(1, 0)) { + context.beginPath(); + context.moveTo(c * tileSize + tileSize * .9, r * tileSize - tileSize * 0); + context.lineTo(c * tileSize + tileSize * .2, r * tileSize); + context.bezierCurveTo(c * tileSize - tileSize * .2, r * tileSize - tileSize * .05, c * tileSize - tileSize * .15, r * tileSize + tileSize * .5, c * tileSize + tileSize * .1, r * tileSize + tileSize * .25); + context.bezierCurveTo(c * tileSize + tileSize * .05, r * tileSize + tileSize * .3, c * tileSize + tileSize * .3, r * tileSize + tileSize * .4, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .35, r * tileSize + tileSize * .4, c * tileSize + tileSize * .6, r * tileSize + tileSize * .4, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .75, r * tileSize + tileSize * .3, c * tileSize + tileSize * .8, r * tileSize + tileSize * .4, c * tileSize + tileSize * .9, r * tileSize + tileSize * .2); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .1, r * tileSize + tileSize * .4, (c + 1) * tileSize + tileSize * .3, r * tileSize + tileSize * .3, (c + 1) * tileSize, r * tileSize + tileSize * .02); + context.closePath(); + } + else { + context.beginPath(); + context.moveTo(c * tileSize, r * tileSize); + context.lineTo(c * tileSize, r * tileSize + tileSize * .15); + context.bezierCurveTo(c * tileSize + tileSize * 0, r * tileSize + tileSize * .4, c * tileSize + tileSize * .3, r * tileSize + tileSize * .3, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .35, r * tileSize + tileSize * .3, c * tileSize + tileSize * .6, r * tileSize + tileSize * .3, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .75, r * tileSize + tileSize * .4, c * tileSize + tileSize * .9, r * tileSize + tileSize * .3, c * tileSize + tileSize * 1, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize, r * tileSize); + context.closePath(); + } + context.fill(); } - else{ - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize+tileSize*.15); - context.bezierCurveTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.4, c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.3, c*tileSize+tileSize*.6, r*tileSize+tileSize*.3, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize, r*tileSize); - context.closePath(); + else if (!curlyOutline && !isOccupied(0, -1)) { + context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + } - context.fill(); + if (!curlyOutline && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(1, -1)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(1, 1)) context.fillRect((c + complement) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(0, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, tileSize, outlinePixels); + if (!curlyOutline && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!curlyOutline && !isOccupied(1, 0)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); } - else if(!curlyOutline && !isOccupied(0, -1)){ context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - - } - if (!curlyOutline && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (!curlyOutline && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!curlyOutline && !isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); - } - - function drawBushes(r, c, isOccupied){ - if(!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)){ + + function drawBushes(r, c, isOccupied) { + if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)) { /*context.shadowColor = "#666"; context.shadowOffsetX = -.5; context.shadowOffsetY = -.5; context.shadowBlur = 1;*/ - + context.beginPath(); - context.moveTo((c+1)*tileSize, r*tileSize); - context.lineTo((c+1)*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); - context.lineTo((c+1)*tileSize, r*tileSize); + context.moveTo((c + 1) * tileSize, r * tileSize); + context.lineTo((c + 1) * tileSize, r * tileSize - tileSize * .4); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .1, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .2); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .3, r * tileSize - tileSize * .2, (c + 1) * tileSize - tileSize * .4, r * tileSize - tileSize * .1, (c + 1) * tileSize - tileSize * .3, r * tileSize); + context.lineTo((c + 1) * tileSize, r * tileSize); context.closePath(); context.fill(); - + context.beginPath(); - context.moveTo((c+1)*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); + context.moveTo((c + 1) * tileSize, r * tileSize - tileSize * .4); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .1, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .2); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .3, r * tileSize - tileSize * .2, (c + 1) * tileSize - tileSize * .4, r * tileSize - tileSize * .1, (c + 1) * tileSize - tileSize * .3, r * tileSize); } - - if(!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)){ + + if (!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)) { /*context.shadowColor = "#666"; context.shadowOffsetX = .5; context.shadowOffsetY = -.5; context.shadowBlur = 1;*/ - + context.beginPath(); - context.moveTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); - context.lineTo(c*tileSize, r*tileSize); + context.moveTo(c * tileSize, r * tileSize); + context.lineTo(c * tileSize, r * tileSize - tileSize * .4); + context.bezierCurveTo(c * tileSize + tileSize * .1, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .3, r * tileSize - tileSize * .2, c * tileSize + tileSize * .4, r * tileSize - tileSize * .1, c * tileSize + tileSize * .3, r * tileSize); + context.lineTo(c * tileSize, r * tileSize); context.closePath(); context.fill(); - + context.restore(); - + context.beginPath(); - context.moveTo(c*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); + context.moveTo(c * tileSize, r * tileSize - tileSize * .4); + context.bezierCurveTo(c * tileSize + tileSize * .1, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .3, r * tileSize - tileSize * .2, c * tileSize + tileSize * .4, r * tileSize - tileSize * .1, c * tileSize + tileSize * .3, r * tileSize); /*context.strokeStyle = "#7dff1a"; - context.stroke();*/ + context.stroke();*/ } } - - function drawSpikes(r, c, adjacentTiles) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = spikeColors[0]; - - context.beginPath(); - context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes - context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.45, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.55, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.75, y + tileSize * 0.3); - - context.moveTo(x + tileSize * 0.7, y + tileSize * 0.25); //right spikes - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.45); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.55); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.75); - - context.moveTo(x + tileSize * 0.75, y + tileSize * 0.7); //bottom spikes - context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.55, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.45, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.25, y + tileSize * 0.7); - - context.moveTo(x + tileSize * 0.3, y + tileSize * 0.75); //left spikes - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.55); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.45); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); - context.closePath(); - - /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ - context.fill(); - drawSpikeSupports(r, c, isSpike, isWall); - - function isSpike(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === SPIKE; - } - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; + + function drawSpikes(r, c, adjacentTiles) { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = spikeColors[0]; + + context.beginPath(); + context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes + context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.45, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.55, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.75, y + tileSize * 0.3); + + context.moveTo(x + tileSize * 0.7, y + tileSize * 0.25); //right spikes + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.45); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.55); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.75); + + context.moveTo(x + tileSize * 0.75, y + tileSize * 0.7); //bottom spikes + context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.55, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.45, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.25, y + tileSize * 0.7); + + context.moveTo(x + tileSize * 0.3, y + tileSize * 0.75); //left spikes + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.55); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.45); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); + context.closePath(); + + /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ + context.fill(); + drawSpikeSupports(r, c, isSpike, isWall); + + function isSpike(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === SPIKE; + } + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } } - } - - function drawSpikeSupports(r, c, isOccupied, canConnect){ + + function drawSpikeSupports(r, c, isOccupied, canConnect) { var boltBool = false; var occupiedCount = 0; - if(canConnect(0, 1)){ + if (canConnect(0, 1)) { context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize+(tileSize*.3), r*tileSize+(tileSize*.8), tileSize*.4, tileSize*.4); + context.fillRect(c * tileSize + (tileSize * .3), r * tileSize + (tileSize * .8), tileSize * .4, tileSize * .4); boltBool = true; } - if(canConnect(0, -1) && !canConnect(0, 1)){ - if(!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(1, -1)){} - else{ + if (canConnect(0, -1) && !canConnect(0, 1)) { + if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(1, -1)) { } + else { context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize+(tileSize*.3), r*tileSize, tileSize*.4, tileSize*.4); + context.fillRect(c * tileSize + (tileSize * .3), r * tileSize, tileSize * .4, tileSize * .4); boltBool = true; } } - if(canConnect(-1, 0) && !canConnect(0, 1)){ - if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(-1, 1)){} - else{ + if (canConnect(-1, 0) && !canConnect(0, 1)) { + if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(-1, 1)) { } + else { context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize, r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); + context.fillRect(c * tileSize, r * tileSize + (tileSize * .3), tileSize * .4, tileSize * .4); boltBool = true; } } - if(canConnect(1, 0) && !canConnect(0, 1)){ - if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(1, -1) && canConnect(1, 1)){} - else{ + if (canConnect(1, 0) && !canConnect(0, 1)) { + if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(1, -1) && canConnect(1, 1)) { } + else { context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize+(tileSize*.8), r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); + context.fillRect(c * tileSize + (tileSize * .8), r * tileSize + (tileSize * .3), tileSize * .4, tileSize * .4); boltBool = true; } } - + context.fillStyle = spikeColors[2]; - if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING ONE - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4,br:4}, true, false); + if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING ONE + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, { bl: 4, br: 4 }, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize, tileSize*.6, {tl:4,bl:4}, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize, tileSize * .6, { tl: 4, bl: 4 }, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4,tr:4}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, { tl: 4, tr: 4 }, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4,br:4}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { tr: 4, br: 4 }, true, false); boltBool = true; } - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (CORNERS) - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {bl:4}, true, false); - if(!canConnect(1, -1)) boltBool = true; + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING TWO (CORNERS) + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, { bl: 4 }, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { bl: 4 }, true, false); + if (!canConnect(1, -1)) boltBool = true; + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { br: 4 }, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, { br: 4 }, true, false); + if (!canConnect(-1, -1)) boltBool = true; + } + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { tl: 4 }, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, { tl: 4 }, true, false); + if (!canConnect(1, 1)) boltBool = true; + } + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { tr: 4 }, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, { tr: 4 }, true, false); + if (!canConnect(-1, 1)) boltBool = true; } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {br:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {br:4}, true, false); - if(!canConnect(-1, -1)) boltBool = true; + else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING TWO (OPPOSITES) + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tl:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4}, true, false); - if(!canConnect(1, 1)) boltBool = true; - } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tr:4}, true, false); - if(!canConnect(-1, 1)) boltBool = true; - } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (OPPOSITES) - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING THREE + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, 0, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, 0, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, 0, true, false); + boltBool = true; } - else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING THREE - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, 0, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ //TOUCHING FOUR - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { //TOUCHING FOUR + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); //boltBool = true; } - else{ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.6, 0, true, false); + else { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .6, 0, true, false); boltBool = true; } - + if (boltBool) drawBolt(r, c); } - - function drawBolt(r, c){ + + function drawBolt(r, c) { context.strokeStyle = spikeColors[3]; context.beginPath(); - context.arc(c*tileSize+(tileSize*.55), r*tileSize+(tileSize*.45), 4, -.7*Math.PI, .2*Math.PI); - context.lineTo(c*tileSize+(tileSize*.45),r*tileSize+(tileSize*.35)); + context.arc(c * tileSize + (tileSize * .55), r * tileSize + (tileSize * .45), 4, -.7 * Math.PI, .2 * Math.PI); + context.lineTo(c * tileSize + (tileSize * .45), r * tileSize + (tileSize * .35)); context.closePath(); context.fillStyle = spikeColors[3]; context.fill(); context.stroke(); - + context.beginPath(); - context.moveTo(c*tileSize+(tileSize*.43),r*tileSize+(tileSize*.47)); - context.arc(c*tileSize+(tileSize*.48), r*tileSize+(tileSize*.52), 4, .2*Math.PI, -.75*Math.PI); + context.moveTo(c * tileSize + (tileSize * .43), r * tileSize + (tileSize * .47)); + context.arc(c * tileSize + (tileSize * .48), r * tileSize + (tileSize * .52), 4, .2 * Math.PI, -.75 * Math.PI); //context.lineTo(c*tileSize+(tileSize*.4),r*tileSize+(tileSize*.6)); context.closePath(); context.fillStyle = spikeColors[3]; context.fill(); context.stroke(); } - - function drawConnector(context, r1, c1, r2, c2, color) { - // either r1 and r2 or c1 and c2 must be equal - if (r1 > r2 || c1 > c2) { - var rTmp = r1; - var cTmp = c1; - r1 = r2; - c1 = c2; - r2 = rTmp; - c2 = cTmp; - } - var xLo = (c1 + 0.3) * tileSize; - var yLo = (r1 + 0.3) * tileSize; - var xHi = (c2 + 0.45) * tileSize; - var yHi = (r2 + 0.45) * tileSize; - context.fillStyle = color; - context.fillRect(xLo+.15*tileSize, yLo+.15*tileSize, xHi - xLo, yHi - yLo); - } - function drawBlock(block) { - var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); - var rowcols = block.locations.map(function(location) { - return getRowcol(level, location); - }); - rowcols.forEach(function(rowcol) { - var r = rowcol.r + animationDisplacementRowcol.r; - var c = rowcol.c + animationDisplacementRowcol.c; - context.fillStyle = blockColors[0][block.id % blockColors[0].length]; - var outlineThickness = .2; - - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - if (!isAlsoThisBlock(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - if (!isAlsoThisBlock( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (!isAlsoThisBlock(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!isAlsoThisBlock( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); - - function isAlsoThisBlock(dc, dr) { - for (var i = 0; i < rowcols.length; i++) { - var otherRowcol = rowcols[i]; - if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; + + function drawConnector(context, r1, c1, r2, c2, color) { + // either r1 and r2 or c1 and c2 must be equal + if (r1 > r2 || c1 > c2) { + var rTmp = r1; + var cTmp = c1; + r1 = r2; + c1 = c2; + r2 = rTmp; + c2 = cTmp; } - return false; - } - }); - } - function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { - var cx = (c + 0.5) * tileSize; - var cy = (r + 0.5) * tileSize; - context.fillStyle = fillStyle; - context.beginPath(); - context.moveTo(cx, cy); - context.arc(cx, cy, radiusFactor * tileSize/2, quadrant * Math.PI/2, (quadrant + 1) * Math.PI/2); - context.fill(); - } - function drawDiamond(r, c, fillStyle) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = fillStyle; - roundRect(context, x, y, tileSize, tileSize, 10, true, false); - } - function drawCircle(r, c, radiusFactor, fillStyle) { - context.fillStyle = fillStyle; - context.beginPath(); - context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize/2 * radiusFactor, 0, 2*Math.PI); - context.fill(); - } - function drawRect(r, c, fillStyle) { - context.fillStyle = fillStyle; - context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); - } - - function drawCloud(c, x, y){ + var xLo = (c1 + 0.3) * tileSize; + var yLo = (r1 + 0.3) * tileSize; + var xHi = (c2 + 0.45) * tileSize; + var yHi = (r2 + 0.45) * tileSize; + context.fillStyle = color; + context.fillRect(xLo + .15 * tileSize, yLo + .15 * tileSize, xHi - xLo, yHi - yLo); + } + function drawBlock(block) { + var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); + var rowcols = block.locations.map(function (location) { + return getRowcol(level, location); + }); + rowcols.forEach(function (rowcol) { + var r = rowcol.r + animationDisplacementRowcol.r; + var c = rowcol.c + animationDisplacementRowcol.c; + context.fillStyle = blockColors[0][block.id % blockColors[0].length]; + var outlineThickness = .2; + + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + if (!isAlsoThisBlock(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(1, -1)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(-1, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(1, 1)) context.fillRect((c + complement) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + if (!isAlsoThisBlock(0, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, tileSize, outlinePixels); + if (!isAlsoThisBlock(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!isAlsoThisBlock(1, 0)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); + + function isAlsoThisBlock(dc, dr) { + for (var i = 0; i < rowcols.length; i++) { + var otherRowcol = rowcols[i]; + if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; + } + return false; + } + }); + } + function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { + var cx = (c + 0.5) * tileSize; + var cy = (r + 0.5) * tileSize; + context.fillStyle = fillStyle; + context.beginPath(); + context.moveTo(cx, cy); + context.arc(cx, cy, radiusFactor * tileSize / 2, quadrant * Math.PI / 2, (quadrant + 1) * Math.PI / 2); + context.fill(); + } + function drawDiamond(r, c, fillStyle) { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = fillStyle; + roundRect(context, x, y, tileSize, tileSize, 10, true, false); + } + function drawCircle(r, c, radiusFactor, fillStyle) { + context.fillStyle = fillStyle; + context.beginPath(); + context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize / 2 * radiusFactor, 0, 2 * Math.PI); + context.fill(); + } + function drawRect(r, c, fillStyle) { + context.fillStyle = fillStyle; + context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); + } + + function drawCloud(c, x, y) { c.fillStyle = experimentalColors[0]; /*c.beginPath(); c.rect(x, y, tileSize, tileSize); c.fill(); c.closePath();*/ - + c.beginPath(); - c.moveTo(x+tileSize*0, y+tileSize*0); - - c.bezierCurveTo(x+tileSize*0, y-tileSize*.15, x+tileSize*.33, y-tileSize*.15, x+tileSize*.33, y+tileSize*0); - c.bezierCurveTo(x+tileSize*.33, y-tileSize*.15, x+tileSize*.67, y-tileSize*.15, x+tileSize*.67, y+tileSize*0); - c.bezierCurveTo(x+tileSize*.67, y-tileSize*.15, x+tileSize*1, y-tileSize*.15, x+tileSize*1, y+tileSize*0); - - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*0, x+tileSize*1.15, y+tileSize*.33, x+tileSize*1, y+tileSize*.33); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.33, x+tileSize*1.15, y+tileSize*.67, x+tileSize*1, y+tileSize*.67); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.67, x+tileSize*1.15, y+tileSize*1, x+tileSize*1, y+tileSize*1); - - c.bezierCurveTo(x+tileSize*1, y+tileSize*1.15, x+tileSize*.67, y+tileSize*1.15, x+tileSize*.67, y+tileSize*1); - c.bezierCurveTo(x+tileSize*.67, y+tileSize*1.15, x+tileSize*.33, y+tileSize*1.15, x+tileSize*.33, y+tileSize*1); - c.bezierCurveTo(x+tileSize*.33, y+tileSize*1.15, x+tileSize*0, y+tileSize*1.15, x+tileSize*0, y+tileSize*1); - - c.bezierCurveTo(x-tileSize*.15, y+tileSize*1, x-tileSize*.15, y+tileSize*.67, x+tileSize*0, y+tileSize*.67); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*.67, x-tileSize*.15, y+tileSize*.33, x+tileSize*0, y+tileSize*.33); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*.33, x-tileSize*.15, y+tileSize*0, x+tileSize*0, y+tileSize*0); - + c.moveTo(x + tileSize * 0, y + tileSize * 0); + + c.bezierCurveTo(x + tileSize * 0, y - tileSize * .15, x + tileSize * .33, y - tileSize * .15, x + tileSize * .33, y + tileSize * 0); + c.bezierCurveTo(x + tileSize * .33, y - tileSize * .15, x + tileSize * .67, y - tileSize * .15, x + tileSize * .67, y + tileSize * 0); + c.bezierCurveTo(x + tileSize * .67, y - tileSize * .15, x + tileSize * 1, y - tileSize * .15, x + tileSize * 1, y + tileSize * 0); + + c.bezierCurveTo(x + tileSize * 1.15, y + tileSize * 0, x + tileSize * 1.15, y + tileSize * .33, x + tileSize * 1, y + tileSize * .33); + c.bezierCurveTo(x + tileSize * 1.15, y + tileSize * .33, x + tileSize * 1.15, y + tileSize * .67, x + tileSize * 1, y + tileSize * .67); + c.bezierCurveTo(x + tileSize * 1.15, y + tileSize * .67, x + tileSize * 1.15, y + tileSize * 1, x + tileSize * 1, y + tileSize * 1); + + c.bezierCurveTo(x + tileSize * 1, y + tileSize * 1.15, x + tileSize * .67, y + tileSize * 1.15, x + tileSize * .67, y + tileSize * 1); + c.bezierCurveTo(x + tileSize * .67, y + tileSize * 1.15, x + tileSize * .33, y + tileSize * 1.15, x + tileSize * .33, y + tileSize * 1); + c.bezierCurveTo(x + tileSize * .33, y + tileSize * 1.15, x + tileSize * 0, y + tileSize * 1.15, x + tileSize * 0, y + tileSize * 1); + + c.bezierCurveTo(x - tileSize * .15, y + tileSize * 1, x - tileSize * .15, y + tileSize * .67, x + tileSize * 0, y + tileSize * .67); + c.bezierCurveTo(x - tileSize * .15, y + tileSize * .67, x - tileSize * .15, y + tileSize * .33, x + tileSize * 0, y + tileSize * .33); + c.bezierCurveTo(x - tileSize * .15, y + tileSize * .33, x - tileSize * .15, y + tileSize * 0, x + tileSize * 0, y + tileSize * 0); + c.closePath(); c.fill(); //c.stroke(); } -function drawFace(snake, headCol, headRow, orientation){ - var x = headCol * tileSize; - var y = headRow * tileSize; - - var scaleFactor = 1.5; - var scale1; - var scale2; - var eye1 = tileSize*.8; - var eye2 = tileSize*.4; - - var eyeSize = tileSize/5; - var eyeRotation = 2; - var z1, z2, z3, z4, z5, z6, z7, z8; - var a1, a2, a3, a4, a5, a6, a7, a8; - var beakRotation = 1.5; - var arcDirection = false; - - switch(orientation){ - case 0: //red up and blue left - z1 = eye2; - z2 = tileSize-eye1; - z3 = eye2; - z4 = tileSize-eye2; - z5 = eye2; - z6 = tileSize-eye1; - z7 = eye2; - z8 = tileSize-eye2 - eyeRotation = 1.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize*.7; - a2 = tileSize-tileSize*.7; - a3 = tileSize*.7; - a4 = -tileSize*.3; - a5 = tileSize*.7; - a6 = tileSize*.3; - a7 = tileSize/6; - a8 = 0; - beakRotation = 1; - arcDirection = false; - break; - case 1: //red right and blue up - z1 = eye1; - z2 = eye2; - z3 = eye2; - z4 = eye2; - z5 = eye1; - z6 = eye2; - z7 = eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize*1.3; - a4 = tileSize*.7; - a5 = tileSize*.7; - a6 = tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = false; - break; - case 2: //red down and blue right - z1 = tileSize-eye2; - z2 = eye1; - z3 = tileSize-eye2; - z4 = eye2; - z5 = tileSize-eye2; - z6 = eye1; - z7 = tileSize-eye2; - z8 = eye2; - eyeRotation = 2.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize-tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize-tileSize*.7; - a4 = tileSize*1.3; - a5 = tileSize-tileSize*.7; - a6 = tileSize*.7; - a7 = tileSize/6; - a8 = 0; - beakRotation = 1; - arcDirection = true; - break; - case 3: //red left and blue down - z1 = tileSize-eye1; - z2 = tileSize-eye2; - z3 = tileSize-eye2; - z4 = tileSize-eye2; - z5 = tileSize-eye1; - z6 = tileSize-eye2; - z7 = tileSize-eye2; - z8 = tileSize-eye2; - eyeRotation = 3; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize-tileSize*.7; - a2 = tileSize-tileSize*.7; - a3 = tileSize-tileSize*1.3; - a4 = tileSize-tileSize*.7; - a5 = tileSize-tileSize*.7; - a6 = tileSize-tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = true; - break; - case 4: //green up and yellow right - z1 = tileSize-eye2; - z2 = tileSize-eye1; - z3 = tileSize-eye2; - z4 = tileSize-eye2; - z5 = tileSize-eye2; - z6 = tileSize-eye1; - z7 = tileSize-eye2; - z8 = tileSize-eye2 - eyeRotation = 2.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize-tileSize*.7; - a2 = tileSize-tileSize*.7; - a3 = tileSize-tileSize*.7; - a4 = -tileSize*.3; - a5 = tileSize-tileSize*.7; - a6 = tileSize*.3; - a7 = tileSize/6; - a8 = 0; - beakRotation = 1; - arcDirection = false; - break; - case 5: //green right and yellow down - z1 = eye1; - z2 = tileSize-eye2; - z3 = eye2; - z4 = tileSize-eye2; - z5 = eye1; - z6 = tileSize-eye2; - z7 = eye2; - z8 = tileSize-eye2; - eyeRotation = 3; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize*.7; - a2 = tileSize-tileSize*.7; - a3 = tileSize*1.3; - a4 = tileSize-tileSize*.7; - a5 = tileSize*.7; - a6 = tileSize-tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = false; - break; - case 6: //green down and yellow left - z1 = eye2; - z2 = eye1; - z3 = eye2; - z4 = eye2; - z5 = eye2; - z6 = eye1; - z7 = eye2; - z8 = eye2; - eyeRotation = 1.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize*.7; - a4 = tileSize*1.3; - a5 = tileSize*.7; - a6 = tileSize*.7; - a7 = tileSize/6; - a8 = 0; - beakRotation = 1; - arcDirection = true; - break; - case 7: //green left and yellow up - z1 = tileSize-eye1; - z2 = eye2; - z3 = tileSize-eye2; - z4 = eye2; - z5 = tileSize-eye1; - z6 = eye2; - z7 = tileSize-eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize-tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize-tileSize*1.3; - a4 = tileSize*.7; - a5 = tileSize-tileSize*.7; - a6 = tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = true; - break; - case 10: //single unit snake - z1 = eye1; - z2 = eye2; - z3 = eye2; - z4 = eye2; - z5 = eye1; - z6 = eye2; - z7 = eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize*1.3; - a4 = tileSize*.7; - a5 = tileSize*.7; - a6 = tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = false; - break; - } - - if (snake === activeSnakeId) { //draw eyes for active snake only - context.fillStyle = "white"; - context.save(); - context.scale(scale1,scale2); - context.beginPath(); - context.arc((x+z1)/scale1, (y+z2)/scale2, eyeSize, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); + function drawFace(snake, headCol, headRow, orientation) { + var x = headCol * tileSize; + var y = headRow * tileSize; + + var scaleFactor = 1.5; + var scale1; + var scale2; + var eye1 = tileSize * .8; + var eye2 = tileSize * .4; + + var eyeSize = tileSize / 5; + var eyeRotation = 2; + var z1, z2, z3, z4, z5, z6, z7, z8; + var a1, a2, a3, a4, a5, a6, a7, a8; + var beakRotation = 1.5; + var arcDirection = false; + + switch (orientation) { + case 0: //red up and blue left + z1 = eye2; + z2 = tileSize - eye1; + z3 = eye2; + z4 = tileSize - eye2; + z5 = eye2; + z6 = tileSize - eye1; + z7 = eye2; + z8 = tileSize - eye2 + eyeRotation = 1.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize * .7; + a2 = tileSize - tileSize * .7; + a3 = tileSize * .7; + a4 = -tileSize * .3; + a5 = tileSize * .7; + a6 = tileSize * .3; + a7 = tileSize / 6; + a8 = 0; + beakRotation = 1; + arcDirection = false; + break; + case 1: //red right and blue up + z1 = eye1; + z2 = eye2; + z3 = eye2; + z4 = eye2; + z5 = eye1; + z6 = eye2; + z7 = eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize * 1.3; + a4 = tileSize * .7; + a5 = tileSize * .7; + a6 = tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = false; + break; + case 2: //red down and blue right + z1 = tileSize - eye2; + z2 = eye1; + z3 = tileSize - eye2; + z4 = eye2; + z5 = tileSize - eye2; + z6 = eye1; + z7 = tileSize - eye2; + z8 = eye2; + eyeRotation = 2.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize - tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize - tileSize * .7; + a4 = tileSize * 1.3; + a5 = tileSize - tileSize * .7; + a6 = tileSize * .7; + a7 = tileSize / 6; + a8 = 0; + beakRotation = 1; + arcDirection = true; + break; + case 3: //red left and blue down + z1 = tileSize - eye1; + z2 = tileSize - eye2; + z3 = tileSize - eye2; + z4 = tileSize - eye2; + z5 = tileSize - eye1; + z6 = tileSize - eye2; + z7 = tileSize - eye2; + z8 = tileSize - eye2; + eyeRotation = 3; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize - tileSize * .7; + a2 = tileSize - tileSize * .7; + a3 = tileSize - tileSize * 1.3; + a4 = tileSize - tileSize * .7; + a5 = tileSize - tileSize * .7; + a6 = tileSize - tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = true; + break; + case 4: //green up and yellow right + z1 = tileSize - eye2; + z2 = tileSize - eye1; + z3 = tileSize - eye2; + z4 = tileSize - eye2; + z5 = tileSize - eye2; + z6 = tileSize - eye1; + z7 = tileSize - eye2; + z8 = tileSize - eye2 + eyeRotation = 2.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize - tileSize * .7; + a2 = tileSize - tileSize * .7; + a3 = tileSize - tileSize * .7; + a4 = -tileSize * .3; + a5 = tileSize - tileSize * .7; + a6 = tileSize * .3; + a7 = tileSize / 6; + a8 = 0; + beakRotation = 1; + arcDirection = false; + break; + case 5: //green right and yellow down + z1 = eye1; + z2 = tileSize - eye2; + z3 = eye2; + z4 = tileSize - eye2; + z5 = eye1; + z6 = tileSize - eye2; + z7 = eye2; + z8 = tileSize - eye2; + eyeRotation = 3; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize * .7; + a2 = tileSize - tileSize * .7; + a3 = tileSize * 1.3; + a4 = tileSize - tileSize * .7; + a5 = tileSize * .7; + a6 = tileSize - tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = false; + break; + case 6: //green down and yellow left + z1 = eye2; + z2 = eye1; + z3 = eye2; + z4 = eye2; + z5 = eye2; + z6 = eye1; + z7 = eye2; + z8 = eye2; + eyeRotation = 1.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize * .7; + a4 = tileSize * 1.3; + a5 = tileSize * .7; + a6 = tileSize * .7; + a7 = tileSize / 6; + a8 = 0; + beakRotation = 1; + arcDirection = true; + break; + case 7: //green left and yellow up + z1 = tileSize - eye1; + z2 = eye2; + z3 = tileSize - eye2; + z4 = eye2; + z5 = tileSize - eye1; + z6 = eye2; + z7 = tileSize - eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize - tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize - tileSize * 1.3; + a4 = tileSize * .7; + a5 = tileSize - tileSize * .7; + a6 = tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = true; + break; + case 10: //single unit snake + z1 = eye1; + z2 = eye2; + z3 = eye2; + z4 = eye2; + z5 = eye1; + z6 = eye2; + z7 = eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize * 1.3; + a4 = tileSize * .7; + a5 = tileSize * .7; + a6 = tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = false; + break; + } - context.fillStyle = "white"; - context.save(); - context.scale(scale1,scale2); - context.beginPath(); - context.arc((x+z3)/scale1, (y+z4)/scale2, eyeSize, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); + if (snake === activeSnakeId) { //draw eyes for active snake only + context.fillStyle = "white"; + context.save(); + context.scale(scale1, scale2); + context.beginPath(); + context.arc((x + z1) / scale1, (y + z2) / scale2, eyeSize, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); - context.fillStyle = "black"; - context.save(); - context.scale(scale1,scale2); - context.beginPath(); - context.arc((x+z5)/scale1, (y+z6)/scale2, eyeSize/2, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); + context.fillStyle = "white"; + context.save(); + context.scale(scale1, scale2); + context.beginPath(); + context.arc((x + z3) / scale1, (y + z4) / scale2, eyeSize, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); - context.fillStyle = "black"; - context.save(); - context.scale(scale1,scale2); + context.fillStyle = "black"; + context.save(); + context.scale(scale1, scale2); + context.beginPath(); + context.arc((x + z5) / scale1, (y + z6) / scale2, eyeSize / 2, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + + context.fillStyle = "black"; + context.save(); + context.scale(scale1, scale2); + context.beginPath(); + context.arc((x + z7) / scale1, (y + z8) / scale2, eyeSize / 2, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + } + + //beak + context.fillStyle = "#F9921C"; context.beginPath(); - context.arc((x+z7)/scale1, (y+z8)/scale2, eyeSize/2, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.arc(x + a1, y + a2, tileSize / 6, (beakRotation - 1) * Math.PI, beakRotation * Math.PI, arcDirection); + context.lineTo(x + a3, y + a4); + context.lineTo(x + a5 + a7, y + a6 + a8); context.closePath(); - context.restore(); context.fill(); } - - //beak - context.fillStyle = "#F9921C"; - context.beginPath(); - context.arc(x+a1, y+a2, tileSize/6, (beakRotation-1)*Math.PI, beakRotation*Math.PI, arcDirection); - context.lineTo(x+a3, y+a4); - context.lineTo(x+a5+a7, y+a6+a8); - context.closePath(); - context.fill(); -} - + function roundRect(ctx, x, y, width, height, radius, fill, stroke) { //Gooby - if (typeof stroke === 'undefined') { - stroke = true; - } - if (typeof radius === 'undefined') { - radius = 5; - } - if (typeof radius === 'number') { - radius = {tl: radius, tr: radius, br: radius, bl: radius}; - } else { - var defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0}; - for (var side in defaultRadius) { - radius[side] = radius[side] || defaultRadius[side]; + if (typeof stroke === 'undefined') { + stroke = true; + } + if (typeof radius === 'undefined') { + radius = 5; + } + if (typeof radius === 'number') { + radius = { tl: radius, tr: radius, br: radius, bl: radius }; + } else { + var defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 }; + for (var side in defaultRadius) { + radius[side] = radius[side] || defaultRadius[side]; + } + } + ctx.beginPath(); + ctx.moveTo(x + radius.tl, y); + ctx.lineTo(x + width - radius.tr, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); + ctx.lineTo(x + width, y + height - radius.br); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); + ctx.lineTo(x + radius.bl, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl); + ctx.lineTo(x, y + radius.tl); + ctx.quadraticCurveTo(x, y, x + radius.tl, y); + ctx.closePath(); + if (fill) { + ctx.fill(); + } + if (stroke) { + ctx.stroke(); } - } - ctx.beginPath(); - ctx.moveTo(x + radius.tl, y); - ctx.lineTo(x + width - radius.tr, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); - ctx.lineTo(x + width, y + height - radius.br); - ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); - ctx.lineTo(x + radius.bl, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl); - ctx.lineTo(x, y + radius.tl); - ctx.quadraticCurveTo(x, y, x + radius.tl, y); - ctx.closePath(); - if (fill) { - ctx.fill(); - } - if (stroke) { - ctx.stroke(); - } } - -function shadeColor(color, percent) { - var R = parseInt(color.substring(1,3),16); - var G = parseInt(color.substring(3,5),16); - var B = parseInt(color.substring(5,7),16); + function shadeColor(color, percent) { - R = parseInt(R * (100 + percent) / 100); - G = parseInt(G * (100 + percent) / 100); - B = parseInt(B * (100 + percent) / 100); + var R = parseInt(color.substring(1, 3), 16); + var G = parseInt(color.substring(3, 5), 16); + var B = parseInt(color.substring(5, 7), 16); - R = (R<255)?R:255; - G = (G<255)?G:255; - B = (B<255)?B:255; + R = parseInt(R * (100 + percent) / 100); + G = parseInt(G * (100 + percent) / 100); + B = parseInt(B * (100 + percent) / 100); - var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16)); - var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16)); - var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16)); + R = (R < 255) ? R : 255; + G = (G < 255) ? G : 255; + B = (B < 255) ? B : 255; - return "#"+RR+GG+BB; -} + var RR = ((R.toString(16).length == 1) ? "0" + R.toString(16) : R.toString(16)); + var GG = ((G.toString(16).length == 1) ? "0" + G.toString(16) : G.toString(16)); + var BB = ((B.toString(16).length == 1) ? "0" + B.toString(16) : B.toString(16)); + + return "#" + RR + GG + BB; + } - - function drawR(r,c,fillStyle){ //Gooby + + function drawR(r, c, fillStyle) { //Gooby context.fillStyle = fillStyle; var cornerRadius = 20; context.lineJoin = "round"; context.lineWidth = 1; - context.strokeRect(c*tileSize, r*tileSize, tileSize, tileSize); + context.strokeRect(c * tileSize, r * tileSize, tileSize, tileSize); //context.fillRect(c*tileSize, r*tileSize, tileSize, tileSize); } - function drawGrid() { - var buffer = document.createElement("canvas"); - buffer.width = canvas.width; - buffer.height = canvas.height; - var localContext = buffer.getContext("2d"); + function drawGrid() { + var buffer = document.createElement("canvas"); + buffer.width = canvas.width; + buffer.height = canvas.height; + var localContext = buffer.getContext("2d"); + + localContext.strokeStyle = "#fff"; + localContext.beginPath(); + for (var r = 0; r < level.height; r++) { + localContext.moveTo(0, tileSize * r); + localContext.lineTo(tileSize * level.width, tileSize * r); + } + for (var c = 0; c < level.width; c++) { + localContext.moveTo(tileSize * c, 0); + localContext.lineTo(tileSize * c, tileSize * level.height); + } + localContext.stroke(); - localContext.strokeStyle = "#fff"; - localContext.beginPath(); - for (var r = 0; r < level.height; r++) { - localContext.moveTo(0, tileSize*r); - localContext.lineTo(tileSize*level.width, tileSize*r); - } - for (var c = 0; c < level.width; c++) { - localContext.moveTo(tileSize*c, 0); - localContext.lineTo(tileSize*c, tileSize*level.height); + context.save(); + context.globalAlpha = 0.4; + context.drawImage(buffer, 0, 0); + context.restore(); } - localContext.stroke(); - - context.save(); - context.globalAlpha = 0.4; - context.drawImage(buffer, 0, 0); - context.restore(); - } } function findAnimation(animationTypes, objectId) { - if (animationQueueCursor === animationQueue.length) return null; - var currentAnimation = animationQueue[animationQueueCursor]; - for (var i = 1; i < currentAnimation.length; i++) { - var animation = currentAnimation[i]; - if (animationTypes.indexOf(animation[0]) !== -1 && animation[1] === objectId) return animation; - } + if (animationQueueCursor === animationQueue.length) return null; + var currentAnimation = animationQueue[animationQueueCursor]; + for (var i = 1; i < currentAnimation.length; i++) { + var animation = currentAnimation[i]; + if (animationTypes.indexOf(animation[0]) !== -1 && animation[1] === objectId) return animation; + } } function findAnimationDisplacementRowcol(objectType, objectId) { - var dr = 0; - var dc = 0; - var animationTypes = [ - "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK - "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK - ]; - // skip the current one - for (var i = animationQueueCursor + 1; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === objectId) { - dr += animation[2]; - dc += animation[3]; - } + var dr = 0; + var dc = 0; + var animationTypes = [ + "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK + "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK + ]; + // skip the current one + for (var i = animationQueueCursor + 1; i < animationQueue.length; i++) { + var animations = animationQueue[i]; + for (var j = 1; j < animations.length; j++) { + var animation = animations[j]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === objectId) { + dr += animation[2]; + dc += animation[3]; + } + } } - } - var movementAnimation = findAnimation(animationTypes, objectId); - if (movementAnimation != null) { - dr += movementAnimation[2] * (1 - animationProgress); - dc += movementAnimation[3] * (1 - animationProgress); - } - return {r: -dr, c: -dc}; + var movementAnimation = findAnimation(animationTypes, objectId); + if (movementAnimation != null) { + dr += movementAnimation[2] * (1 - animationProgress); + dc += movementAnimation[3] * (1 - animationProgress); + } + return { r: -dr, c: -dc }; } function hasFutureRemoveAnimation(object) { - var animationTypes = [ - EXIT_SNAKE, - DIE_BLOCK, - ]; - for (var i = animationQueueCursor; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === object.id) { - return true; - } + var animationTypes = [ + EXIT_SNAKE, + DIE_BLOCK, + ]; + for (var i = animationQueueCursor; i < animationQueue.length; i++) { + var animations = animationQueue[i]; + for (var j = 1; j < animations.length; j++) { + var animation = animations[j]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === object.id) { + return true; + } + } } - } } function previewPaste(hoverR, hoverC) { - var offsetR = hoverR - clipboardOffsetRowcol.r; - var offsetC = hoverC - clipboardOffsetRowcol.c; - - var newLevel = JSON.parse(JSON.stringify(level)); - var selectedLocations = []; - var selectedObjects = []; - clipboardData.selectedLocations.forEach(function(location) { - var tileCode = clipboardData.level.map[location]; - var rowcol = getRowcol(clipboardData.level, location); - var r = rowcol.r + offsetR; - var c = rowcol.c + offsetC; - if (!isInBounds(newLevel, r, c)) return; - var newLocation = getLocation(newLevel, r, c); - newLevel.map[newLocation] = tileCode; - selectedLocations.push(newLocation); - }); - clipboardData.selectedObjects.forEach(function(object) { - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(clipboardData.level, object.locations[i]); - rowcol.r += offsetR; - rowcol.c += offsetC; - if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { - // this location is oob - if (object.type === SNAKE) { - // snakes must be completely in bounds - return; + var offsetR = hoverR - clipboardOffsetRowcol.r; + var offsetC = hoverC - clipboardOffsetRowcol.c; + + var newLevel = JSON.parse(JSON.stringify(level)); + var selectedLocations = []; + var selectedObjects = []; + clipboardData.selectedLocations.forEach(function (location) { + var tileCode = clipboardData.level.map[location]; + var rowcol = getRowcol(clipboardData.level, location); + var r = rowcol.r + offsetR; + var c = rowcol.c + offsetC; + if (!isInBounds(newLevel, r, c)) return; + var newLocation = getLocation(newLevel, r, c); + newLevel.map[newLocation] = tileCode; + selectedLocations.push(newLocation); + }); + clipboardData.selectedObjects.forEach(function (object) { + var newLocations = []; + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(clipboardData.level, object.locations[i]); + rowcol.r += offsetR; + rowcol.c += offsetC; + if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { + // this location is oob + if (object.type === SNAKE) { + // snakes must be completely in bounds + return; + } + // just skip it + continue; + } + var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); + newLocations.push(newLocation); } - // just skip it - continue; - } - var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); - newLocations.push(newLocation); - } - if (newLocations.length === 0) return; // can't have a non-present object - var newObject = JSON.parse(JSON.stringify(object)); - newObject.locations = newLocations; - selectedObjects.push(newObject); - }); - return { - level: newLevel, - selectedLocations: selectedLocations, - selectedObjects: selectedObjects, - }; + if (newLocations.length === 0) return; // can't have a non-present object + var newObject = JSON.parse(JSON.stringify(object)); + newObject.locations = newLocations; + selectedObjects.push(newObject); + }); + return { + level: newLevel, + selectedLocations: selectedLocations, + selectedObjects: selectedObjects, + }; } function getNaiveOrthogonalPath(a, b) { - // does not include a, but does include b. - var rowcolA = getRowcol(level, a); - var rowcolB = getRowcol(level, b); - var path = []; - if (rowcolA.r < rowcolB.r) { - for (var r = rowcolA.r; r < rowcolB.r; r++) { - path.push(getLocation(level, r + 1, rowcolA.c)); - } - } else { - for (var r = rowcolA.r; r > rowcolB.r; r--) { - path.push(getLocation(level, r - 1, rowcolA.c)); - } - } - if (rowcolA.c < rowcolB.c) { - for (var c = rowcolA.c; c < rowcolB.c; c++) { - path.push(getLocation(level, rowcolB.r, c + 1)); + // does not include a, but does include b. + var rowcolA = getRowcol(level, a); + var rowcolB = getRowcol(level, b); + var path = []; + if (rowcolA.r < rowcolB.r) { + for (var r = rowcolA.r; r < rowcolB.r; r++) { + path.push(getLocation(level, r + 1, rowcolA.c)); + } + } else { + for (var r = rowcolA.r; r > rowcolB.r; r--) { + path.push(getLocation(level, r - 1, rowcolA.c)); + } } - } else { - for (var c = rowcolA.c; c > rowcolB.c; c--) { - path.push(getLocation(level, rowcolB.r, c - 1)); + if (rowcolA.c < rowcolB.c) { + for (var c = rowcolA.c; c < rowcolB.c; c++) { + path.push(getLocation(level, rowcolB.r, c + 1)); + } + } else { + for (var c = rowcolA.c; c > rowcolB.c; c--) { + path.push(getLocation(level, rowcolB.r, c - 1)); + } } - } - return path; + return path; } function identityFunction(x) { - return x; + return x; } function compareId(a, b) { - return operatorCompare(a.id, b.id); + return operatorCompare(a.id, b.id); } function operatorCompare(a, b) { - return a < b ? -1 : a > b ? 1 : 0; + return a < b ? -1 : a > b ? 1 : 0; } function clamp(value, min, max) { - if (value < min) return min; - if (value > max) return max; - return value; + if (value < min) return min; + if (value > max) return max; + return value; } function copyArray(array) { - return array.map(identityFunction); + return array.map(identityFunction); } function getSetIntersection(array1, array2) { - if (array1.length * array2.length === 0) return []; - return array1.filter(function(x) { return array2.indexOf(x) !== -1; }); + if (array1.length * array2.length === 0) return []; + return array1.filter(function (x) { return array2.indexOf(x) !== -1; }); } function makeScaleCoordinatesFunction(width1, width2) { - return function(location) { - return location + (width2 - width1) * Math.floor(location / width1); - }; + return function (location) { + return location + (width2 - width1) * Math.floor(location / width1); + }; } var expectHash; -window.addEventListener("hashchange", function() { - if (location.hash === expectHash) { - // We're in the middle of saveLevel() or saveReplay(). - // Don't react to that event. - expectHash = null; - return; - } - // The user typed into the url bar or used Back/Forward browser buttons, etc. - loadFromLocationHash(); +window.addEventListener("hashchange", function () { + if (location.hash === expectHash) { + // We're in the middle of saveLevel() or saveReplay(). + // Don't react to that event. + expectHash = null; + return; + } + // The user typed into the url bar or used Back/Forward browser buttons, etc. + loadFromLocationHash(); }); function loadFromLocationHash() { - var hashSegments = location.hash.split("#"); - hashSegments.shift(); // first element is always "" - if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; - var hashPairs = hashSegments.map(function(segment) { - var equalsIndex = segment.indexOf("="); - if (equalsIndex === -1) return ["", segment]; // bad - return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; - }); - - if (hashPairs[0][0] !== "level") return false; - try { - var level = parseLevel(hashPairs[0][1]); - } catch (e) { - alert(e); - return false; - } - loadLevel(level); - if (hashPairs.length > 1) { + var hashSegments = location.hash.split("#"); + hashSegments.shift(); // first element is always "" + if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; + var hashPairs = hashSegments.map(function (segment) { + var equalsIndex = segment.indexOf("="); + if (equalsIndex === -1) return ["", segment]; // bad + return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; + }); + + if (hashPairs[0][0] !== "level") return false; try { - if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); - parseAndLoadReplay(hashPairs[1][1]); + var level = parseLevel(hashPairs[0][1]); } catch (e) { - alert(e); - return false; + alert(e); + return false; + } + loadLevel(level); + if (hashPairs.length > 1) { + try { + if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); + parseAndLoadReplay(hashPairs[1][1]); + } catch (e) { + alert(e); + return false; + } } - } - return true; + return true; } // run test suite @@ -4418,5 +4434,5 @@ testTime = new Date().getTime() - testTime; loadPersistentState(); if (!loadFromLocationHash()) { - loadLevel(parseLevel(exampleLevel)); + loadLevel(parseLevel(exampleLevel)); } From 5ed7038942ce04ecb64f937015ededc702f4e7cc Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 23 Feb 2020 20:08:09 -0500 Subject: [PATCH 290/577] Update Main.js --- Main.js | 7046 +++++++++++++++++++++++++++---------------------------- 1 file changed, 3515 insertions(+), 3531 deletions(-) diff --git a/Main.js b/Main.js index c6958198..c59f9fb9 100644 --- a/Main.js +++ b/Main.js @@ -1,7 +1,7 @@ function unreachable() { return new Error("unreachable"); } if (typeof VERSION !== "undefined") { - document.getElementById("versionSpan").innerHTML = - '' + VERSION.tag + ''; + document.getElementById("versionSpan").innerHTML = + '' + VERSION.tag + ''; } /*$(document).ready(function() { var fruits1 = getObjectsOfType(FRUIT); @@ -51,30 +51,30 @@ var cs = false; var tileSize = 34; var level; -var unmoveStuff = { undoStack: [], redoStack: [], spanId: "movesSpan", undoButtonId: "unmoveButton", redoButtonId: "removeButton" }; -var uneditStuff = { undoStack: [], redoStack: [], spanId: "editsSpan", undoButtonId: "uneditButton", redoButtonId: "reeditButton" }; +var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; +var uneditStuff = {undoStack:[], redoStack:[], spanId:"editsSpan", undoButtonId:"uneditButton", redoButtonId:"reeditButton"}; var paradoxes = []; function loadLevel(newLevel) { - level = newLevel; - currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); - - activateAnySnakePlease(); - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - undoStuffChanged(unmoveStuff); - uneditStuff.undoStack = []; - uneditStuff.redoStack = []; - undoStuffChanged(uneditStuff); - blockSupportRenderCache = {}; - render(); + level = newLevel; + currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); + + activateAnySnakePlease(); + unmoveStuff.undoStack = []; + unmoveStuff.redoStack = []; + undoStuffChanged(unmoveStuff); + uneditStuff.undoStack = []; + uneditStuff.redoStack = []; + undoStuffChanged(uneditStuff); + blockSupportRenderCache = {}; + render(); } var magicNumber_v0 = "3tFRIoTU"; -var magicNumber = "HyRr4JK1"; +var magicNumber = "HyRr4JK1"; var exampleLevel = magicNumber_v0 + "&" + - "17&31" + - "?" + + "17&31" + + "?" + "0000000000000000000000000000000" + "0000000000000000000000000000000" + "0000000000000000000000000000000" + @@ -92,591 +92,591 @@ var exampleLevel = magicNumber_v0 + "&" + "0000011111111101111111111100000" + "0000001111111100111111111100000" + "0000001111111000111111111100000" + - "/" + - "s0 ?351&350&349/" + - "f0 ?328/" + - "f1 ?366/"; + "/" + + "s0 ?351&350&349/" + + "f0 ?328/" + + "f1 ?366/"; var testLevel_v0 = "3tFRIoTU&5&5?0005*00300024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/"; var testLevel_v0_converted = "HyRr4JK1&5&5?0005*4024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/f0?8/"; function parseLevel(string) { - // magic number - var cursor = 0; - skipWhitespace(); - var versionTag = string.substr(cursor, magicNumber.length); - switch (versionTag) { - case magicNumber_v0: - case magicNumber: break; - default: throw new Error("not a snakefall level"); + // magic number + var cursor = 0; + skipWhitespace(); + var versionTag = string.substr(cursor, magicNumber.length); + switch (versionTag) { + case magicNumber_v0: + case magicNumber: break; + default: throw new Error("not a snakefall level"); + } + cursor += magicNumber.length; + consumeKeyword("&"); + + var level = { + height: -1, + width: -1, + map: [], + objects: [], + }; + + // height, width + level.height = readInt(); + consumeKeyword("&"); + level.width = readInt(); + + // map + var mapData = readRun(); + mapData = decompressSerialization(mapData); + if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); + var upconvertedObjects = []; + var fruitCount = 0; + var tileCounter = 0; + for (var i = 0; i < mapData.length; i++) { + var tileCode = mapData[i].charCodeAt(0); + if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { + // fruit used to be a tile code. now it's an object. + upconvertedObjects.push({ + type: FRUIT, + id: fruitCount++, + dead: false, // unused + locations: [i], + }); + tileCode = SPACE; } - cursor += magicNumber.length; - consumeKeyword("&"); - - var level = { - height: -1, - width: -1, - map: [], - objects: [], + if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; + if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); + level.map.push(tileCode); + } + + // objects + skipWhitespace(); + while (cursor < string.length) { + var object = { + type: "?", + id: -1, + dead: false, + locations: [], }; - // height, width - level.height = readInt(); - consumeKeyword("&"); - level.width = readInt(); - - // map - var mapData = readRun(); - mapData = decompressSerialization(mapData); - if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); - var upconvertedObjects = []; - var fruitCount = 0; - var tileCounter = 0; - for (var i = 0; i < mapData.length; i++) { - var tileCode = mapData[i].charCodeAt(0); - if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { - // fruit used to be a tile code. now it's an object. - upconvertedObjects.push({ - type: FRUIT, - id: fruitCount++, - dead: false, // unused - locations: [i], - }); - tileCode = SPACE; - } - if (tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; - if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); - level.map.push(tileCode); - } + // type + object.type = string[cursor]; + var locationsLimit; + if (object.type === SNAKE) locationsLimit = -1; + else if (object.type === BLOCK) locationsLimit = -1; + else if (object.type === FRUIT || object.type === POISON_FRUIT) locationsLimit = 1; + else throw parserError("expected object type code"); + cursor += 1; + + // id + object.id = readInt(); + + // locations + var locationsData = readRun(); + var locationStrings = locationsData.split("&"); + if (locationStrings.length === 0) throw parserError("locations must be non-empty"); + if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); + + locationStrings.forEach(function(locationString) { + var location = parseInt(locationString); + if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); + object.locations.push(location); + }); - // objects + level.objects.push(object); skipWhitespace(); - while (cursor < string.length) { - var object = { - type: "?", - id: -1, - dead: false, - locations: [], - }; - - // type - object.type = string[cursor]; - var locationsLimit; - if (object.type === SNAKE) locationsLimit = -1; - else if (object.type === BLOCK) locationsLimit = -1; - else if (object.type === FRUIT || object.type === POISON_FRUIT) locationsLimit = 1; - else throw parserError("expected object type code"); - cursor += 1; - - // id - object.id = readInt(); - - // locations - var locationsData = readRun(); - var locationStrings = locationsData.split("&"); - if (locationStrings.length === 0) throw parserError("locations must be non-empty"); - if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); - - locationStrings.forEach(function (locationString) { - var location = parseInt(locationString); - if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); - object.locations.push(location); - }); - - level.objects.push(object); - skipWhitespace(); - } - - if (tileCounter > 0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL
    contains experimental elements"; + } + + if(tileCounter>0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL
    contains experimental elements"; else document.getElementById("levelType").innerHTML = "STANDARD LEVEL
    does not contain experimental elements"; + + for (var i = 0; i < upconvertedObjects.length; i++) { + level.objects.push(upconvertedObjects[i]); + } - for (var i = 0; i < upconvertedObjects.length; i++) { - level.objects.push(upconvertedObjects[i]); - } - - return level; + return level; - function skipWhitespace() { - while (" \n\t\r".indexOf(string[cursor]) !== -1) { - cursor += 1; - } - } - function consumeKeyword(keyword) { - skipWhitespace(); - if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); - cursor += 1; + function skipWhitespace() { + while (" \n\t\r".indexOf(string[cursor]) !== -1) { + cursor += 1; } - function readInt() { - skipWhitespace(); - for (var i = cursor; i < string.length; i++) { - if ("0123456789".indexOf(string[i]) === -1) break; - } - var substring = string.substring(cursor, i); - if (substring.length === 0) throw parserError("expected int"); - cursor = i; - return parseInt(substring, 10); - } - function readRun() { - consumeKeyword("?"); - var endIndex = string.indexOf("/", cursor); - var substring = string.substring(cursor, endIndex); - cursor = endIndex + 1; - return substring; - } - function parserError(message) { - return new Error("parse error at position " + cursor + ": " + message); + } + function consumeKeyword(keyword) { + skipWhitespace(); + if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); + cursor += 1; + } + function readInt() { + skipWhitespace(); + for (var i = cursor; i < string.length; i++) { + if ("0123456789".indexOf(string[i]) === -1) break; } + var substring = string.substring(cursor, i); + if (substring.length === 0) throw parserError("expected int"); + cursor = i; + return parseInt(substring, 10); + } + function readRun() { + consumeKeyword("?"); + var endIndex = string.indexOf("/", cursor); + var substring = string.substring(cursor, endIndex); + cursor = endIndex + 1; + return substring; + } + function parserError(message) { + return new Error("parse error at position " + cursor + ": " + message); + } } function serializeTileCode(tileCode) { - return String.fromCharCode(tileCode); + return String.fromCharCode(tileCode); } function stringifyLevel(level) { - var output = magicNumber + "&"; - output += level.height + "&" + level.width + "\n"; + var output = magicNumber + "&"; + output += level.height + "&" + level.width + "\n"; - output += "?\n"; - for (var r = 0; r < level.height; r++) { - output += " " + level.map.slice(r * level.width, (r + 1) * level.width).map(serializeTileCode).join("") + "\n"; - } - output += "/\n"; + output += "?\n"; + for (var r = 0; r < level.height; r++) { + output += " " + level.map.slice(r * level.width, (r + 1) * level.width).map(serializeTileCode).join("") + "\n"; + } + output += "/\n"; - output += serializeObjects(level.objects); + output += serializeObjects(level.objects); - // sanity check - var shouldBeTheSame = parseLevel(output); - if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken + // sanity check + var shouldBeTheSame = parseLevel(output); + if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken - return output; + return output; } function serializeObjects(objects) { - var output = ""; - for (var i = 0; i < objects.length; i++) { - var object = objects[i]; - output += object.type + object.id + " "; - output += "?" + object.locations.join("&") + "/\n"; - } - return output; + var output = ""; + for (var i = 0; i < objects.length; i++) { + var object = objects[i]; + output += object.type + object.id + " "; + output += "?" + object.locations.join("&") + "/\n"; + } + return output; } function serializeObjectState(object) { - if (object == null) return [0, []]; - return [object.dead, copyArray(object.locations)]; + if (object == null) return [0,[]]; + return [object.dead, copyArray(object.locations)]; } var base66 = "----0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; function compressSerialization(string) { - string = string.replace(/\s+/g, ""); - // run-length encode several 0's in a row, etc. - // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) - var result = ""; - var runStart = 0; - for (var i = 1; i < string.length + 1; i++) { - var runLength = i - runStart; - if (string[i] === string[runStart] && runLength < base66.length - 1) continue; - // end of run - if (runLength >= 4) { - // compress - result += "*" + base66[runLength] + string[runStart]; - } else { - // literal - result += string.substring(runStart, i); - } - runStart = i; + string = string.replace(/\s+/g, ""); + // run-length encode several 0's in a row, etc. + // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) + var result = ""; + var runStart = 0; + for (var i = 1; i < string.length + 1; i++) { + var runLength = i - runStart; + if (string[i] === string[runStart] && runLength < base66.length - 1) continue; + // end of run + if (runLength >= 4) { + // compress + result += "*" + base66[runLength] + string[runStart]; + } else { + // literal + result += string.substring(runStart, i); } - return result; + runStart = i; + } + return result; } function decompressSerialization(string) { - string = string.replace(/\s+/g, ""); - var result = ""; - for (var i = 0; i < string.length; i++) { - if (string[i] === "*") { - i += 1; - var runLength = base66.indexOf(string[i]); - i += 1; - var char = string[i]; - for (var j = 0; j < runLength; j++) { - result += char; - } - } else { - result += string[i]; - } + string = string.replace(/\s+/g, ""); + var result = ""; + for (var i = 0; i < string.length; i++) { + if (string[i] === "*") { + i += 1; + var runLength = base66.indexOf(string[i]); + i += 1; + var char = string[i]; + for (var j = 0; j < runLength; j++) { + result += char; + } + } else { + result += string[i]; } - return result; + } + return result; } var replayMagicNumber = "nmGTi8PB"; function stringifyReplay() { - var output = replayMagicNumber + "&"; - // only specify the snake id in an input if it's different from the previous. - // the first snake index is 0 to optimize for the single-snake case. - var currentSnakeId = 0; - for (var i = 0; i < unmoveStuff.undoStack.length; i++) { - var firstChange = unmoveStuff.undoStack[i][0]; - if (firstChange[0] !== "i") throw unreachable(); - var snakeId = firstChange[1]; - var dr = firstChange[2]; - var dc = firstChange[3]; - var directionCode; - if (dr === -1 && dc === 0) directionCode = "u"; - else if (dr === 0 && dc === -1) directionCode = "l"; - else if (dr === 1 && dc === 0) directionCode = "d"; - else if (dr === 0 && dc === 1) directionCode = "r"; - else throw unreachable(); - if (snakeId !== currentSnakeId) { - output += snakeId; // int to string - currentSnakeId = snakeId; - } - output += directionCode; + var output = replayMagicNumber + "&"; + // only specify the snake id in an input if it's different from the previous. + // the first snake index is 0 to optimize for the single-snake case. + var currentSnakeId = 0; + for (var i = 0; i < unmoveStuff.undoStack.length; i++) { + var firstChange = unmoveStuff.undoStack[i][0]; + if (firstChange[0] !== "i") throw unreachable(); + var snakeId = firstChange[1]; + var dr = firstChange[2]; + var dc = firstChange[3]; + var directionCode; + if (dr ===-1 && dc === 0) directionCode = "u"; + else if (dr === 0 && dc ===-1) directionCode = "l"; + else if (dr === 1 && dc === 0) directionCode = "d"; + else if (dr === 0 && dc === 1) directionCode = "r"; + else throw unreachable(); + if (snakeId !== currentSnakeId) { + output += snakeId; // int to string + currentSnakeId = snakeId; } - return output; + output += directionCode; + } + return output; } function parseAndLoadReplay(string) { - string = decompressSerialization(string); - var expectedPrefix = replayMagicNumber + "&"; - if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); - var cursor = expectedPrefix.length; - - // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. - activeSnakeId = 0; - while (cursor < string.length) { - var snakeIdStr = ""; - var c = string.charAt(cursor); - cursor += 1; - while ('0' <= c && c <= '9') { - snakeIdStr += c; - if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); - c = string.charAt(cursor); - cursor += 1; - } - if (snakeIdStr.length > 0) { - activeSnakeId = parseInt(snakeIdStr); - // don't just validate when switching snakes, but on every move. - } + string = decompressSerialization(string); + var expectedPrefix = replayMagicNumber + "&"; + if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); + var cursor = expectedPrefix.length; + + // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. + activeSnakeId = 0; + while (cursor < string.length) { + var snakeIdStr = ""; + var c = string.charAt(cursor); + cursor += 1; + while ('0' <= c && c <= '9') { + snakeIdStr += c; + if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); + c = string.charAt(cursor); + cursor += 1; + } + if (snakeIdStr.length > 0) { + activeSnakeId = parseInt(snakeIdStr); + // don't just validate when switching snakes, but on every move. + } - // doing a move. - if (!getSnakes().some(function (snake) { - return snake.id === activeSnakeId; - })) { - throw new Error("invalid snake id: " + activeSnakeId); - } - switch (c) { - case 'l': move(0, -1); break; - case 'u': move(-1, 0); break; - case 'r': move(0, 1); break; - case 'd': move(1, 0); break; - default: throw new Error("replay string has invalid direction: " + c); - } + // doing a move. + if (!getSnakes().some(function(snake) { + return snake.id === activeSnakeId; + })) { + throw new Error("invalid snake id: " + activeSnakeId); + } + switch (c) { + case 'l': move( 0, -1); break; + case 'u': move(-1, 0); break; + case 'r': move( 0, 1); break; + case 'd': move( 1, 0); break; + default: throw new Error("replay string has invalid direction: " + c); } + } - // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. - reset(unmoveStuff); - document.getElementById("removeButton").classList.add("click-me"); + // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. + reset(unmoveStuff); + document.getElementById("removeButton").classList.add("click-me"); } var currentSerializedLevel; function saveLevel() { - if (isDead()) return alert("Can't save while you're dead!"); - var serializedLevel = compressSerialization(stringifyLevel(level)); - currentSerializedLevel = serializedLevel; - var hash = "#level=" + serializedLevel; - expectHash = hash; - location.hash = hash; - - // This marks a starting point for solving the level. - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - editorHasBeenTouched = false; - undoStuffChanged(unmoveStuff); + if (isDead()) return alert("Can't save while you're dead!"); + var serializedLevel = compressSerialization(stringifyLevel(level)); + currentSerializedLevel = serializedLevel; + var hash = "#level=" + serializedLevel; + expectHash = hash; + location.hash = hash; + + // This marks a starting point for solving the level. + unmoveStuff.undoStack = []; + unmoveStuff.redoStack = []; + editorHasBeenTouched = false; + undoStuffChanged(unmoveStuff); } function saveReplay() { - if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); - // preserve the level in the url bar. - var hash = "#level=" + currentSerializedLevel; - if (dirtyState === REPLAY_DIRTY) { - // there is a replay to save - hash += "#replay=" + compressSerialization(stringifyReplay()); - } - expectHash = hash; - location.hash = hash; + if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); + // preserve the level in the url bar. + var hash = "#level=" + currentSerializedLevel; + if (dirtyState === REPLAY_DIRTY) { + // there is a replay to save + hash += "#replay=" + compressSerialization(stringifyReplay()); + } + expectHash = hash; + location.hash = hash; } function deepEquals(a, b) { - if (a == null) return b == null; - if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; - if (Array.isArray(a)) { - if (!Array.isArray(b)) return false; - if (a.length !== b.length) return false; - for (var i = 0; i < a.length; i++) { - if (!deepEquals(a[i], b[i])) return false; - } - return true; - } - // must be objects - var aKeys = Object.keys(a); - var bKeys = Object.keys(b); - if (aKeys.length !== bKeys.length) return false; - aKeys.sort(); - bKeys.sort(); - if (!deepEquals(aKeys, bKeys)) return false; - for (var i = 0; i < aKeys.length; i++) { - if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; + if (a == null) return b == null; + if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; + if (Array.isArray(a)) { + if (!Array.isArray(b)) return false; + if (a.length !== b.length) return false; + for (var i = 0; i < a.length; i++) { + if (!deepEquals(a[i], b[i])) return false; } return true; + } + // must be objects + var aKeys = Object.keys(a); + var bKeys = Object.keys(b); + if (aKeys.length !== bKeys.length) return false; + aKeys.sort(); + bKeys.sort(); + if (!deepEquals(aKeys, bKeys)) return false; + for (var i = 0; i < aKeys.length; i++) { + if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; + } + return true; } function getLocation(level, r, c) { - if (!isInBounds(level, r, c)) throw unreachable(); - return r * level.width + c; + if (!isInBounds(level, r, c)) throw unreachable(); + return r * level.width + c; } function getRowcol(level, location) { - if (location < 0 || location >= level.width * level.height) throw unreachable(); - var r = Math.floor(location / level.width); - var c = location % level.width; - return { r: r, c: c }; + if (location < 0 || location >= level.width * level.height) throw unreachable(); + var r = Math.floor(location / level.width); + var c = location % level.width; + return {r:r, c:c}; } function isInBounds(level, r, c) { - if (c < 0 || c >= level.width) return false;; - if (r < 0 || r >= level.height) return false;; - return true; + if (c < 0 || c >= level.width) return false;; + if (r < 0 || r >= level.height) return false;; + return true; } function offsetLocation(location, dr, dc) { - var rowcol = getRowcol(level, location); - return getLocation(level, rowcol.r + dr, rowcol.c + dc); + var rowcol = getRowcol(level, location); + return getLocation(level, rowcol.r + dr, rowcol.c + dc); } var SHIFT = 1; var CTRL = 2; var ALT = 4; -document.addEventListener("keydown", function (event) { - var modifierMask = ( - (event.shiftKey ? SHIFT : 0) | - (event.ctrlKey ? CTRL : 0) | - (event.altKey ? ALT : 0) - ); - switch (event.keyCode) { - case 37: // left - if (modifierMask === 0) { move(0, -1); break; } - return; - case 38: // up - if (modifierMask === 0) { move(-1, 0); break; } - return; - case 39: // right - if (modifierMask === 0) { move(0, 1); break; } - return; - case 40: // down - if (modifierMask === 0) { move(1, 0); break; } - return; - case 8: // backspace - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Q".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Z".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { undo(uneditStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL | SHIFT) { redo(uneditStuff); break; } - return; - case "Y".charCodeAt(0): - if (modifierMask === 0) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { redo(uneditStuff); break; } - return; - case "R".charCodeAt(0): - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } - if (modifierMask === 0) { reset(unmoveStuff); break; } - if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLR); break; } - return; - case 220: // backslash - if (modifierMask === 0) { toggleShowEditor(); break; } - return; - case "A".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, -1); break; } - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PORTAL); break; } - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } - if (persistentState.showEditor && modifierMask === CTRL) { selectAll(); break; } - return; - case "E".charCodeAt(0): - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(EXIT); break; } - return; - case 46: // delete - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - return; - case "W".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(WOODPLATFORM); break; } - if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(WATER); break; } - return; - case "S".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPIKE); break; } - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(SNAKE); break; } - if (persistentState.showEditor && modifierMask === CTRL) { saveLevel(); break; } - if (!persistentState.showEditor && modifierMask === CTRL) { saveReplay(); break; } - if (modifierMask === (CTRL | SHIFT)) { saveReplay(); break; } - return; - case "X".charCodeAt(0): - if (persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } - return; - case "F".charCodeAt(0): - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(POISON_FRUIT); break; } - return; - case "D".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } - if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLD); break; } - return; - case "B".charCodeAt(0): - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(BUBBLE); break; } - return; - case "P".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } - return; - case "U".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLU); break; } - return; - case "L".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOSEDLIFT); break; } - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(OPENLIFT); break; } - if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLL); break; } - return; - case "G".charCodeAt(0): - if (modifierMask === 0) { toggleGrid(); break; } - if (persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } - return; - case "C".charCodeAt(0): - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } - if (persistentState.showEditor && modifierMask === SHIFT) { toggleCollision(); break; } - if (persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } - return; - case "V".charCodeAt(0): - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(LAVA); break; } - if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } - case "T".charCodeAt(0): - toggleTheme(); break; - return; - case 32: // spacebar - case 9: // tab - if (modifierMask === 0) { switchSnakes(1); break; } - if (modifierMask === SHIFT) { switchSnakes(-1); break; } - return; - case "1".charCodeAt(0): - case "2".charCodeAt(0): - case "3".charCodeAt(0): - case "4".charCodeAt(0): - var index = event.keyCode - "1".charCodeAt(0); - var delta; - if (modifierMask === 0) { - delta = 1; - } else if (modifierMask === SHIFT) { - delta = -1; - } else return; - if (isAlive()) { - (function () { - var snakes = findSnakesOfColor(index); - if (snakes.length === 0) return; - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; - } - } - activeSnakeId = snakes[0].id; - })(); +document.addEventListener("keydown", function(event) { + var modifierMask = ( + (event.shiftKey ? SHIFT : 0) | + (event.ctrlKey ? CTRL : 0) | + (event.altKey ? ALT : 0) + ); + switch (event.keyCode) { + case 37: // left + if (modifierMask === 0) { move(0, -1); break; } + return; + case 38: // up + if (modifierMask === 0) { move(-1, 0); break; } + return; + case 39: // right + if (modifierMask === 0) { move(0, 1); break; } + return; + case 40: // down + if (modifierMask === 0) { move(1, 0); break; } + return; + case 8: // backspace + if (modifierMask === 0) { undo(unmoveStuff); break; } + if (modifierMask === SHIFT) { redo(unmoveStuff); break; } + return; + case "Q".charCodeAt(0): + if (modifierMask === 0) { undo(unmoveStuff); break; } + if (modifierMask === SHIFT) { redo(unmoveStuff); break; } + return; + case "Z".charCodeAt(0): + if (modifierMask === 0) { undo(unmoveStuff); break; } + if (modifierMask === SHIFT) { redo(unmoveStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL) { undo(uneditStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL|SHIFT) { redo(uneditStuff); break; } + return; + case "Y".charCodeAt(0): + if (modifierMask === 0) { redo(unmoveStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL) { redo(uneditStuff); break; } + return; + case "R".charCodeAt(0): + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } + if (modifierMask === 0) { reset(unmoveStuff); break; } + if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLR); break; } + return; + case 220: // backslash + if (modifierMask === 0) { toggleShowEditor(); break; } + return; + case "A".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(0, -1); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PORTAL); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { selectAll(); break; } + return; + case "E".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(EXIT); break; } + return; + case 46: // delete + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } + return; + case "W".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(WOODPLATFORM); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(WATER); break; } + return; + case "S".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPIKE); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(SNAKE); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { saveLevel(); break; } + if (!persistentState.showEditor && modifierMask === CTRL) { saveReplay(); break; } + if (modifierMask === (CTRL|SHIFT)) { saveReplay(); break; } + return; + case "X".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } + return; + case "F".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(POISON_FRUIT); break; } + return; + case "D".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLD); break; } + return; + case "B".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(BUBBLE); break; } + return; + case "P".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } + return; + case "U".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLU); break; } + return; + case "L".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOSEDLIFT); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(OPENLIFT); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLL); break; } + return; + case "G".charCodeAt(0): + if (modifierMask === 0) { toggleGrid(); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } + return; + case "C".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } + if ( persistentState.showEditor && modifierMask === SHIFT) { toggleCollision(); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } + return; + case "V".charCodeAt(0): + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(LAVA); break; } + if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } + case "T".charCodeAt(0): + toggleTheme(); break; + return; + case 32: // spacebar + case 9: // tab + if (modifierMask === 0) { switchSnakes( 1); break; } + if (modifierMask === SHIFT) { switchSnakes(-1); break; } + return; + case "1".charCodeAt(0): + case "2".charCodeAt(0): + case "3".charCodeAt(0): + case "4".charCodeAt(0): + var index = event.keyCode - "1".charCodeAt(0); + var delta; + if (modifierMask === 0) { + delta = 1; + } else if (modifierMask === SHIFT) { + delta = -1; + } else return; + if (isAlive()) { + (function() { + var snakes = findSnakesOfColor(index); + if (snakes.length === 0) return; + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) { + activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; + return; } - break; - case 27: // escape - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(null); break; } - return; - default: return; - } - event.preventDefault(); - render(); + } + activeSnakeId = snakes[0].id; + })(); + } + break; + case 27: // escape + if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(null); break; } + return; + default: return; + } + event.preventDefault(); + render(); }); -document.getElementById("switchSnakesButton").addEventListener("click", function () { - switchSnakes(1); - render(); +document.getElementById("switchSnakesButton").addEventListener("click", function() { + switchSnakes(1); + render(); }); function switchSnakes(delta) { - if (!isAlive()) return; - var snakes = getSnakes(); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; - } + if (!isAlive()) return; + var snakes = getSnakes(); + snakes.sort(compareId); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) { + activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; + return; } - activeSnakeId = snakes[0].id; + } + activeSnakeId = snakes[0].id; } -document.getElementById("showGridButton").addEventListener("click", function () { - toggleGrid(); +document.getElementById("showGridButton").addEventListener("click", function() { + toggleGrid(); }); -document.getElementById("saveProgressButton").addEventListener("click", function () { - saveReplay(); +document.getElementById("saveProgressButton").addEventListener("click", function() { + saveReplay(); }); -document.getElementById("checkSolutionButton").addEventListener("click", function () { - redoAll(unmoveStuff); +document.getElementById("checkSolutionButton").addEventListener("click", function() { + redoAll(unmoveStuff); }); -document.getElementById("restartButton").addEventListener("click", function () { - reset(unmoveStuff); - render(); +document.getElementById("restartButton").addEventListener("click", function() { + reset(unmoveStuff); + render(); }); -document.getElementById("unmoveButton").addEventListener("click", function () { - undo(unmoveStuff); - render(); +document.getElementById("unmoveButton").addEventListener("click", function() { + undo(unmoveStuff); + render(); }); -document.getElementById("removeButton").addEventListener("click", function () { - redo(unmoveStuff); - render(); +document.getElementById("removeButton").addEventListener("click", function() { + redo(unmoveStuff); + render(); }); -document.getElementById("showHideEditor").addEventListener("click", function () { - toggleShowEditor(); +document.getElementById("showHideEditor").addEventListener("click", function() { + toggleShowEditor(); }); function toggleShowEditor() { - persistentState.showEditor = !persistentState.showEditor; - savePersistentState(); - showEditorChanged(); + persistentState.showEditor = !persistentState.showEditor; + savePersistentState(); + showEditorChanged(); } function toggleGrid() { - persistentState.showGrid = !persistentState.showGrid; - savePersistentState(); - render(); + persistentState.showGrid = !persistentState.showGrid; + savePersistentState(); + render(); } -["serializationTextarea", "shareLinkTextbox"].forEach(function (id) { - document.getElementById(id).addEventListener("keydown", function (event) { - // let things work normally - event.stopPropagation(); - }); +["serializationTextarea", "shareLinkTextbox"].forEach(function(id) { + document.getElementById(id).addEventListener("keydown", function(event) { + // let things work normally + event.stopPropagation(); + }); }); -document.getElementById("submitSerializationButton").addEventListener("click", function () { - var string = document.getElementById("serializationTextarea").value; - try { - var newLevel = parseLevel(string); - } catch (e) { - alert(e); - return; - } - loadLevel(newLevel); +document.getElementById("submitSerializationButton").addEventListener("click", function() { + var string = document.getElementById("serializationTextarea").value; + try { + var newLevel = parseLevel(string); + } catch (e) { + alert(e); + return; + } + loadLevel(newLevel); }); -document.getElementById("shareLinkTextbox").addEventListener("focus", function () { - setTimeout(function () { - document.getElementById("shareLinkTextbox").select(); - }, 0); +document.getElementById("shareLinkTextbox").addEventListener("focus", function() { + setTimeout(function() { + document.getElementById("shareLinkTextbox").select(); + }, 0); }); var paintBrushTileCode = null; @@ -689,765 +689,765 @@ var resizeDragAnchorRowcol = null; var clipboardData = null; var clipboardOffsetRowcol = null; var paintButtonIdAndTileCodes = [ - ["resizeButton", "resize"], - ["selectButton", "select"], - ["pasteButton", "paste"], - ["paintSpaceButton", SPACE], - ["paintWallButton", WALL], - ["paintSpikeButton", SPIKE], - ["paintExitButton", EXIT], - ["paintFruitButton", FRUIT], - ["paintPoisonFruitButton", POISON_FRUIT], - ["paintPortalButton", PORTAL], - ["paintPlatformButton", PLATFORM], - ["paintWoodPlatformButton", WOODPLATFORM], - ["paintOneWayWallUButton", ONEWAYWALLU], - ["paintOneWayWallDButton", ONEWAYWALLD], - ["paintOneWayWallLButton", ONEWAYWALLL], - ["paintOneWayWallRButton", ONEWAYWALLR], - ["paintClosedLiftButton", CLOSEDLIFT], - ["paintOpenLiftButton", OPENLIFT], - ["paintCloudButton", CLOUD], - ["paintBubbleButton", BUBBLE], - ["paintLavaButton", LAVA], - ["paintWaterButton", WATER], - ["paintSnakeButton", SNAKE], - ["paintBlockButton", BLOCK], + ["resizeButton", "resize"], + ["selectButton", "select"], + ["pasteButton", "paste"], + ["paintSpaceButton", SPACE], + ["paintWallButton", WALL], + ["paintSpikeButton", SPIKE], + ["paintExitButton", EXIT], + ["paintFruitButton", FRUIT], + ["paintPoisonFruitButton", POISON_FRUIT], + ["paintPortalButton", PORTAL], + ["paintPlatformButton", PLATFORM], + ["paintWoodPlatformButton", WOODPLATFORM], + ["paintOneWayWallUButton", ONEWAYWALLU], + ["paintOneWayWallDButton", ONEWAYWALLD], + ["paintOneWayWallLButton", ONEWAYWALLL], + ["paintOneWayWallRButton", ONEWAYWALLR], + ["paintClosedLiftButton", CLOSEDLIFT], + ["paintOpenLiftButton", OPENLIFT], + ["paintCloudButton", CLOUD], + ["paintBubbleButton", BUBBLE], + ["paintLavaButton", LAVA], + ["paintWaterButton", WATER], + ["paintSnakeButton", SNAKE], + ["paintBlockButton", BLOCK], ]; -paintButtonIdAndTileCodes.forEach(function (pair) { - var id = pair[0]; - var tileCode = pair[1]; - document.getElementById(id).addEventListener("click", function () { - setPaintBrushTileCode(tileCode); - }); +paintButtonIdAndTileCodes.forEach(function(pair) { + var id = pair[0]; + var tileCode = pair[1]; + document.getElementById(id).addEventListener("click", function() { + setPaintBrushTileCode(tileCode); + }); }); -document.getElementById("uneditButton").addEventListener("click", function () { - undo(uneditStuff); - render(); +document.getElementById("uneditButton").addEventListener("click", function() { + undo(uneditStuff); + render(); }); -document.getElementById("reeditButton").addEventListener("click", function () { - redo(uneditStuff); - render(); +document.getElementById("reeditButton").addEventListener("click", function() { + redo(uneditStuff); + render(); }); -document.getElementById("saveLevelButton").addEventListener("click", function () { - saveLevel(); +document.getElementById("saveLevelButton").addEventListener("click", function() { + saveLevel(); }); -document.getElementById("copyButton").addEventListener("click", function () { - copySelection(); +document.getElementById("copyButton").addEventListener("click", function() { + copySelection(); }); -document.getElementById("cutButton").addEventListener("click", function () { - cutSelection(); +document.getElementById("cutButton").addEventListener("click", function() { + cutSelection(); }); -document.getElementById("cheatGravityButton").addEventListener("click", function () { - toggleGravity(); +document.getElementById("cheatGravityButton").addEventListener("click", function() { + toggleGravity(); }); -document.getElementById("cheatCollisionButton").addEventListener("click", function () { - toggleCollision(); +document.getElementById("cheatCollisionButton").addEventListener("click", function() { + toggleCollision(); }); -document.getElementById("themeButton").addEventListener("click", function () { - toggleTheme(); +document.getElementById("themeButton").addEventListener("click", function() { + toggleTheme(); }); function toggleTheme() { - if (themeCounter < themes.length - 1) themeCounter++; + if(themeCounter"; } function toggleGravity() { - isGravityEnabled = !isGravityEnabled; - isCollisionEnabled = true; - refreshCheatButtonText(); + isGravityEnabled = !isGravityEnabled; + isCollisionEnabled = true; + refreshCheatButtonText(); } function toggleCollision() { - isCollisionEnabled = !isCollisionEnabled; - isGravityEnabled = false; - refreshCheatButtonText(); + isCollisionEnabled = !isCollisionEnabled; + isGravityEnabled = false; + refreshCheatButtonText(); } function refreshCheatButtonText() { - document.getElementById("cheatGravityButton").textContent = isGravityEnabled ? "Gravity: ON" : "Gravity: OFF"; - document.getElementById("cheatGravityButton").style.background = isGravityEnabled ? "" : "#f88"; + document.getElementById("cheatGravityButton").textContent = isGravityEnabled ? "Gravity: ON" : "Gravity: OFF"; + document.getElementById("cheatGravityButton").style.background = isGravityEnabled ? "" : "#f88"; - document.getElementById("cheatCollisionButton").textContent = isCollisionEnabled ? "Collision: ON" : "Collision: OFF"; - document.getElementById("cheatCollisionButton").style.background = isCollisionEnabled ? "" : "#f88"; + document.getElementById("cheatCollisionButton").textContent = isCollisionEnabled ? "Collision: ON" : "Collision: OFF"; + document.getElementById("cheatCollisionButton").style.background = isCollisionEnabled ? "" : "#f88"; } // be careful with location vs rowcol, because this variable is used when resizing var lastDraggingRowcol = null; var hoverLocation = null; var draggingChangeLog = null; -canvas.addEventListener("mousedown", function (event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - var location = getLocationFromEvent(event); - if (persistentState.showEditor && paintBrushTileCode != null) { - // editor tool - lastDraggingRowcol = getRowcol(level, location); - if (paintBrushTileCode === "select") selectionStart = location; - if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; - draggingChangeLog = []; - paintAtLocation(location, draggingChangeLog); - } else { - // playtime - var object = findObjectAtLocation(location); - if (object == null) return; - if (object.type !== SNAKE) return; - // active snake - activeSnakeId = object.id; - render(); - } +canvas.addEventListener("mousedown", function(event) { + if (event.altKey) return; + if (event.button !== 0) return; + event.preventDefault(); + var location = getLocationFromEvent(event); + if (persistentState.showEditor && paintBrushTileCode != null) { + // editor tool + lastDraggingRowcol = getRowcol(level, location); + if (paintBrushTileCode === "select") selectionStart = location; + if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; + draggingChangeLog = []; + paintAtLocation(location, draggingChangeLog); + } else { + // playtime + var object = findObjectAtLocation(location); + if (object == null) return; + if (object.type !== SNAKE) return; + // active snake + activeSnakeId = object.id; + render(); + } }); -canvas.addEventListener("dblclick", function (event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - if (persistentState.showEditor && paintBrushTileCode === "select") { - // double click with select tool - var location = getLocationFromEvent(event); - var object = findObjectAtLocation(location); - if (object == null) return; - stopDragging(); - if (object.type === SNAKE) { - // edit snakes of this color - paintBrushTileCode = SNAKE; - paintBrushSnakeColorIndex = object.id % snakeColors.length; - } else if (object.type === BLOCK) { - // edit this particular block - paintBrushTileCode = BLOCK; - paintBrushBlockId = object.id; - } else if (object.type === FRUIT) { - // edit fruits, i guess - paintBrushTileCode = FRUIT; - } else if (object.type === POISON_FRUIT) { - // edit poison fruits, i guess - paintBrushTileCode = POISON_FRUIT; - } - else throw unreachable(); - paintBrushTileCodeChanged(); +canvas.addEventListener("dblclick", function(event) { + if (event.altKey) return; + if (event.button !== 0) return; + event.preventDefault(); + if (persistentState.showEditor && paintBrushTileCode === "select") { + // double click with select tool + var location = getLocationFromEvent(event); + var object = findObjectAtLocation(location); + if (object == null) return; + stopDragging(); + if (object.type === SNAKE) { + // edit snakes of this color + paintBrushTileCode = SNAKE; + paintBrushSnakeColorIndex = object.id % snakeColors.length; + } else if (object.type === BLOCK) { + // edit this particular block + paintBrushTileCode = BLOCK; + paintBrushBlockId = object.id; + } else if (object.type === FRUIT) { + // edit fruits, i guess + paintBrushTileCode = FRUIT; + } else if (object.type === POISON_FRUIT) { + // edit poison fruits, i guess + paintBrushTileCode = POISON_FRUIT; } + else throw unreachable(); + paintBrushTileCodeChanged(); + } }); -document.addEventListener("mouseup", function (event) { - stopDragging(); +document.addEventListener("mouseup", function(event) { + stopDragging(); }); function stopDragging() { - if (lastDraggingRowcol != null) { - // release the draggin' - lastDraggingRowcol = null; - paintBrushObject = null; - resizeDragAnchorRowcol = null; - pushUndo(uneditStuff, draggingChangeLog); - draggingChangeLog = null; - } + if (lastDraggingRowcol != null) { + // release the draggin' + lastDraggingRowcol = null; + paintBrushObject = null; + resizeDragAnchorRowcol = null; + pushUndo(uneditStuff, draggingChangeLog); + draggingChangeLog = null; + } } -canvas.addEventListener("mousemove", function (event) { - if (!persistentState.showEditor) return; - var location = getLocationFromEvent(event); - var mouseRowcol = getRowcol(level, location); - if (lastDraggingRowcol != null) { - // Dragging Force - Through the Fruit and Flames - var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); - // we need to get rowcols for everything before we start dragging, because dragging might resize the world. - var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function (location) { - return getRowcol(level, location); - }); - path.forEach(function (rowcol) { - // convert to location at the last minute in case each of these steps is changing the coordinate system. - paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); - }); - lastDraggingRowcol = mouseRowcol; - hoverLocation = null; - } else { - // hovering - if (hoverLocation !== location) { - hoverLocation = location; - render(); - } - } -}); -canvas.addEventListener("mouseout", function () { +canvas.addEventListener("mousemove", function(event) { + if (!persistentState.showEditor) return; + var location = getLocationFromEvent(event); + var mouseRowcol = getRowcol(level, location); + if (lastDraggingRowcol != null) { + // Dragging Force - Through the Fruit and Flames + var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); + // we need to get rowcols for everything before we start dragging, because dragging might resize the world. + var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function(location) { + return getRowcol(level, location); + }); + path.forEach(function(rowcol) { + // convert to location at the last minute in case each of these steps is changing the coordinate system. + paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); + }); + lastDraggingRowcol = mouseRowcol; + hoverLocation = null; + } else { + // hovering if (hoverLocation !== location) { - // turn off the hover when the mouse leaves - hoverLocation = null; - render(); + hoverLocation = location; + render(); } + } +}); +canvas.addEventListener("mouseout", function() { + if (hoverLocation !== location) { + // turn off the hover when the mouse leaves + hoverLocation = null; + render(); + } }); function getLocationFromEvent(event) { - var r = Math.floor(eventToMouseY(event, canvas) / tileSize); - var c = Math.floor(eventToMouseX(event, canvas) / tileSize); - // since the canvas is centered, the bounding client rect can be half-pixel aligned, - // resulting in slightly out-of-bounds mouse events. - r = clamp(r, 0, level.height); - c = clamp(c, 0, level.width); - return getLocation(level, r, c); + var r = Math.floor(eventToMouseY(event, canvas) / tileSize); + var c = Math.floor(eventToMouseX(event, canvas) / tileSize); + // since the canvas is centered, the bounding client rect can be half-pixel aligned, + // resulting in slightly out-of-bounds mouse events. + r = clamp(r, 0, level.height); + c = clamp(c, 0, level.width); + return getLocation(level, r, c); } function eventToMouseX(event, canvas) { return event.clientX - canvas.getBoundingClientRect().left; } function eventToMouseY(event, canvas) { return event.clientY - canvas.getBoundingClientRect().top; } function selectAll() { - selectionStart = 0; - selectionEnd = level.map.length - 1; - setPaintBrushTileCode("select"); + selectionStart = 0; + selectionEnd = level.map.length - 1; + setPaintBrushTileCode("select"); } function setPaintBrushTileCode(tileCode) { - if (tileCode === "paste") { - // make sure we have something to paste - if (clipboardData == null) return; + if (tileCode === "paste") { + // make sure we have something to paste + if (clipboardData == null) return; + } + if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { + // usually this means to fill in the selection + if (tileCode == null) { + // cancel selection + selectionStart = null; + selectionEnd = null; + return; } - if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { - // usually this means to fill in the selection - if (tileCode == null) { - // cancel selection - selectionStart = null; - selectionEnd = null; - return; - } - // fill in the selection - fillSelection(tileCode); - selectionStart = null; - selectionEnd = null; - return; + // fill in the selection + fillSelection(tileCode); + selectionStart = null; + selectionEnd = null; + return; + } + if (tileCode === SNAKE) { + if (paintBrushTileCode === SNAKE) { + // next snake color + paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; } - if (tileCode === SNAKE) { - if (paintBrushTileCode === SNAKE) { - // next snake color - paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; - } - } else if (tileCode === BLOCK) { - var blocks = getBlocks(); - if (paintBrushTileCode === BLOCK && blocks.length > 0) { - // cycle through block ids - blocks.sort(compareId); - if (paintBrushBlockId != null) { - (function () { - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id === paintBrushBlockId) { - i += 1; - if (i < blocks.length) { - // next block id - paintBrushBlockId = blocks[i].id; - } else { - // new block id - paintBrushBlockId = null; - } - return; - } - } - throw unreachable() - })(); - } else { - // first one - paintBrushBlockId = blocks[0].id; + } else if (tileCode === BLOCK) { + var blocks = getBlocks(); + if (paintBrushTileCode === BLOCK && blocks.length > 0) { + // cycle through block ids + blocks.sort(compareId); + if (paintBrushBlockId != null) { + (function() { + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].id === paintBrushBlockId) { + i += 1; + if (i < blocks.length) { + // next block id + paintBrushBlockId = blocks[i].id; + } else { + // new block id + paintBrushBlockId = null; + } + return; } - } else { - // new block id - paintBrushBlockId = null; - } - } else if (tileCode == null) { - // escape - if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { - // stop editing this block, but keep the block brush selected - tileCode = BLOCK; - paintBrushBlockId = null; - } + } + throw unreachable() + })(); + } else { + // first one + paintBrushBlockId = blocks[0].id; + } + } else { + // new block id + paintBrushBlockId = null; } - paintBrushTileCode = tileCode; - paintBrushTileCodeChanged(); + } else if (tileCode == null) { + // escape + if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { + // stop editing this block, but keep the block brush selected + tileCode = BLOCK; + paintBrushBlockId = null; + } + } + paintBrushTileCode = tileCode; + paintBrushTileCodeChanged(); } function paintBrushTileCodeChanged() { - paintButtonIdAndTileCodes.forEach(function (pair) { - var id = pair[0]; - var tileCode = pair[1]; - var backgroundStyle = ""; - var textColor = ""; - if (tileCode === paintBrushTileCode) { - if (tileCode === SNAKE) { - // show the color of the active snake in the color of the button - backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; - } else { - backgroundStyle = "linear-gradient(#4b91ff, #055ce4)"; - textColor = "white"; - } - } - document.getElementById(id).style.background = backgroundStyle; - document.getElementById(id).style.color = textColor; - }); + paintButtonIdAndTileCodes.forEach(function(pair) { + var id = pair[0]; + var tileCode = pair[1]; + var backgroundStyle = ""; + var textColor = ""; + if (tileCode === paintBrushTileCode) { + if (tileCode === SNAKE) { + // show the color of the active snake in the color of the button + backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; + } else { + backgroundStyle = "linear-gradient(#4b91ff, #055ce4)"; + textColor = "white"; + } + } + document.getElementById(id).style.background = backgroundStyle; + document.getElementById(id).style.color = textColor; + }); - var isSelectionMode = paintBrushTileCode === "select"; - ["cutButton", "copyButton"].forEach(function (id) { - document.getElementById(id).disabled = !isSelectionMode; - }); - document.getElementById("pasteButton").disabled = clipboardData == null; + var isSelectionMode = paintBrushTileCode === "select"; + ["cutButton", "copyButton"].forEach(function (id) { + document.getElementById(id).disabled = !isSelectionMode; + }); + document.getElementById("pasteButton").disabled = clipboardData == null; - render(); + render(); } function cutSelection() { - copySelection(); - fillSelection(SPACE); - render(); + copySelection(); + fillSelection(SPACE); + render(); } function copySelection() { - var selectedLocations = getSelectedLocations(); - if (selectedLocations.length === 0) return; - var selectedObjects = []; - selectedLocations.forEach(function (location) { - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(selectedObjects, object); - }); - setClipboardData({ - level: JSON.parse(JSON.stringify(level)), - selectedLocations: selectedLocations, - selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), - }); + var selectedLocations = getSelectedLocations(); + if (selectedLocations.length === 0) return; + var selectedObjects = []; + selectedLocations.forEach(function(location) { + var object = findObjectAtLocation(location); + if (object != null) addIfNotPresent(selectedObjects, object); + }); + setClipboardData({ + level: JSON.parse(JSON.stringify(level)), + selectedLocations: selectedLocations, + selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), + }); } function setClipboardData(data) { - // find the center - var minR = Infinity; - var maxR = -Infinity; - var minC = Infinity; - var maxC = -Infinity; - data.selectedLocations.forEach(function (location) { - var rowcol = getRowcol(data.level, location); - if (rowcol.r < minR) minR = rowcol.r; - if (rowcol.r > maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var offsetR = Math.floor((minR + maxR) / 2); - var offsetC = Math.floor((minC + maxC) / 2); - - clipboardData = data; - clipboardOffsetRowcol = { r: offsetR, c: offsetC }; - paintBrushTileCodeChanged(); + // find the center + var minR = Infinity; + var maxR = -Infinity; + var minC = Infinity; + var maxC = -Infinity; + data.selectedLocations.forEach(function(location) { + var rowcol = getRowcol(data.level, location); + if (rowcol.r < minR) minR = rowcol.r; + if (rowcol.r > maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var offsetR = Math.floor((minR + maxR) / 2); + var offsetC = Math.floor((minC + maxC) / 2); + + clipboardData = data; + clipboardOffsetRowcol = {r:offsetR, c:offsetC}; + paintBrushTileCodeChanged(); } function fillSelection(tileCode) { - var changeLog = []; - var locations = getSelectedLocations(); - locations.forEach(function (location) { - if (level.map[location] !== tileCode) { - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; - } - removeAnyObjectAtLocation(location, changeLog); - }); - pushUndo(uneditStuff, changeLog); + var changeLog = []; + var locations = getSelectedLocations(); + locations.forEach(function(location) { + if (level.map[location] !== tileCode) { + changeLog.push(["m", location, level.map[location], tileCode]); + level.map[location] = tileCode; + } + removeAnyObjectAtLocation(location, changeLog); + }); + pushUndo(uneditStuff, changeLog); } function getSelectedLocations() { - if (selectionStart == null || selectionEnd == null) return []; - var rowcol1 = getRowcol(level, selectionStart); - var rowcol2 = getRowcol(level, selectionEnd); - var r1 = rowcol1.r; - var c1 = rowcol1.c; - var r2 = rowcol2.r; - var c2 = rowcol2.c; - if (r2 < r1) { - var tmp = r1; - r1 = r2; - r2 = tmp; - } - if (c2 < c1) { - var tmp = c1; - c1 = c2; - c2 = tmp; + if (selectionStart == null || selectionEnd == null) return []; + var rowcol1 = getRowcol(level, selectionStart); + var rowcol2 = getRowcol(level, selectionEnd); + var r1 = rowcol1.r; + var c1 = rowcol1.c; + var r2 = rowcol2.r; + var c2 = rowcol2.c; + if (r2 < r1) { + var tmp = r1; + r1 = r2; + r2 = tmp; + } + if (c2 < c1) { + var tmp = c1; + c1 = c2; + c2 = tmp; + } + var objects = []; + var locations = []; + for (var r = r1; r <= r2; r++) { + for (var c = c1; c <= c2; c++) { + var location = getLocation(level, r, c); + locations.push(location); + var object = findObjectAtLocation(location); + if (object != null) addIfNotPresent(objects, object); } - var objects = []; - var locations = []; - for (var r = r1; r <= r2; r++) { - for (var c = c1; c <= c2; c++) { - var location = getLocation(level, r, c); - locations.push(location); - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(objects, object); - } - } - // select the rest of any partially-selected objects - objects.forEach(function (object) { - object.locations.forEach(function (location) { - addIfNotPresent(locations, location); - }); + } + // select the rest of any partially-selected objects + objects.forEach(function(object) { + object.locations.forEach(function(location) { + addIfNotPresent(locations, location); }); - return locations; + }); + return locations; } function setHeight(newHeight, changeLog) { - if (newHeight < level.height) { - // crop - for (var r = newHeight; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - // also delete non-space tiles - paintTileAtLocation(location, SPACE, changeLog); - } - } - level.map.splice(newHeight * level.width); - } else { - // expand - for (var r = level.height; r < newHeight; r++) { - for (var c = 0; c < level.width; c++) { - level.map.push(SPACE); - } - } + if (newHeight < level.height) { + // crop + for (var r = newHeight; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + removeAnyObjectAtLocation(location, changeLog); + // also delete non-space tiles + paintTileAtLocation(location, SPACE, changeLog); + } } - changeLog.push(["h", level.height, newHeight]); - level.height = newHeight; + level.map.splice(newHeight * level.width); + } else { + // expand + for (var r = level.height; r < newHeight; r++) { + for (var c = 0; c < level.width; c++) { + level.map.push(SPACE); + } + } + } + changeLog.push(["h", level.height, newHeight]); + level.height = newHeight; } function setWidth(newWidth, changeLog) { - if (newWidth < level.width) { - // crop - for (var r = level.height - 1; r >= 0; r--) { - for (var c = level.width - 1; c >= newWidth; c--) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, SPACE, changeLog); - level.map.splice(location, 1); - } - } - } else { - // expand - for (var r = level.height - 1; r >= 0; r--) { - var insertionPoint = level.width * (r + 1); - for (var c = level.width; c < newWidth; c++) { - // boy is this inefficient. ... YOLO! - level.map.splice(insertionPoint, 0, SPACE); - } - } + if (newWidth < level.width) { + // crop + for (var r = level.height - 1; r >= 0; r--) { + for (var c = level.width - 1; c >= newWidth; c--) { + var location = getLocation(level, r, c); + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, SPACE, changeLog); + level.map.splice(location, 1); + } } + } else { + // expand + for (var r = level.height - 1; r >= 0; r--) { + var insertionPoint = level.width * (r + 1); + for (var c = level.width; c < newWidth; c++) { + // boy is this inefficient. ... YOLO! + level.map.splice(insertionPoint, 0, SPACE); + } + } + } - var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); - level.objects.forEach(function (object) { - object.locations = object.locations.map(transformLocation); - }); + var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); + level.objects.forEach(function(object) { + object.locations = object.locations.map(transformLocation); + }); - changeLog.push(["w", level.width, newWidth]); - level.width = newWidth; + changeLog.push(["w", level.width, newWidth]); + level.width = newWidth; } function newSnake(color, location) { - var snakes = findSnakesOfColor(color); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id !== i * snakeColors.length + color) break; - } - return { - type: SNAKE, - id: i * snakeColors.length + color, - dead: false, - locations: [location], - }; + var snakes = findSnakesOfColor(color); + snakes.sort(compareId); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id !== i * snakeColors.length + color) break; + } + return { + type: SNAKE, + id: i * snakeColors.length + color, + dead: false, + locations: [location], + }; } function newBlock(location) { - var blocks = getBlocks(); - blocks.sort(compareId); - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id !== i) break; - } - return { - type: BLOCK, - id: i, - dead: false, // unused - locations: [location], - }; + var blocks = getBlocks(); + blocks.sort(compareId); + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].id !== i) break; + } + return { + type: BLOCK, + id: i, + dead: false, // unused + locations: [location], + }; } function newFruit(location) { - var fruits = getObjectsOfType(FRUIT); - fruits.sort(compareId); - for (var i = 0; i < fruits.length; i++) { - if (fruits[i].id !== i) break; - } - return { - type: FRUIT, - id: i, - dead: false, // unused - locations: [location], - }; + var fruits = getObjectsOfType(FRUIT); + fruits.sort(compareId); + for (var i = 0; i < fruits.length; i++) { + if (fruits[i].id !== i) break; + } + return { + type: FRUIT, + id: i, + dead: false, // unused + locations: [location], + }; } function newPoisonFruit(location) { - var fruits = getObjectsOfType(POISON_FRUIT); - fruits.sort(compareId); - for (var i = 0; i < fruits.length; i++) { - if (fruits[i].id !== i) break; - } - return { - type: POISON_FRUIT, - id: i, - dead: false, // unused - locations: [location], - }; + var fruits = getObjectsOfType(POISON_FRUIT); + fruits.sort(compareId); + for (var i = 0; i < fruits.length; i++) { + if (fruits[i].id !== i) break; + } + return { + type: POISON_FRUIT, + id: i, + dead: false, // unused + locations: [location], + }; } function paintAtLocation(location, changeLog) { - if (typeof paintBrushTileCode === "number") { - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, paintBrushTileCode, changeLog); - } else if (paintBrushTileCode === "resize") { - var toRowcol = getRowcol(level, location); - var dr = toRowcol.r - resizeDragAnchorRowcol.r; - var dc = toRowcol.c - resizeDragAnchorRowcol.c; - resizeDragAnchorRowcol = toRowcol; - if (dr !== 0) setHeight(level.height + dr, changeLog); - if (dc !== 0) setWidth(level.width + dc, changeLog); - } else if (paintBrushTileCode === "select") { - selectionEnd = location; - } else if (paintBrushTileCode === "paste") { - var hoverRowcol = getRowcol(level, location); - var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); - pastedData.selectedLocations.forEach(function (location) { - var tileCode = pastedData.level.map[location]; - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, tileCode, changeLog); - }); - pastedData.selectedObjects.forEach(function (object) { - // refresh the ids so there are no collisions. - if (object.type === SNAKE) { - object.id = newSnake(object.id % snakeColors.length).id; - } else if (object.type === BLOCK) { - object.id = newBlock().id; - } else if (object.type === FRUIT) { - object.id = newFruit().id; - } else if (object.type === POISON_FRUIT) { - object.id = newPoisonFruit().id; - } else throw unreachable(); - level.objects.push(object); - changeLog.push([object.type, object.id, [0, []], serializeObjectState(object)]); - }); - } else if (paintBrushTileCode === SNAKE) { - var oldSnakeSerialization = serializeObjectState(paintBrushObject); - if (paintBrushObject != null) { - // keep dragging - if (paintBrushObject.locations[0] === location) return; // we just did that - // watch out for self-intersection - var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); - if (selfIntersectionIndex !== -1) { - // truncate from here back - paintBrushObject.locations.splice(selfIntersectionIndex); - } - } + if (typeof paintBrushTileCode === "number") { + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, paintBrushTileCode, changeLog); + } else if (paintBrushTileCode === "resize") { + var toRowcol = getRowcol(level, location); + var dr = toRowcol.r - resizeDragAnchorRowcol.r; + var dc = toRowcol.c - resizeDragAnchorRowcol.c; + resizeDragAnchorRowcol = toRowcol; + if (dr !== 0) setHeight(level.height + dr, changeLog); + if (dc !== 0) setWidth(level.width + dc, changeLog); + } else if (paintBrushTileCode === "select") { + selectionEnd = location; + } else if (paintBrushTileCode === "paste") { + var hoverRowcol = getRowcol(level, location); + var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); + pastedData.selectedLocations.forEach(function(location) { + var tileCode = pastedData.level.map[location]; + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, tileCode, changeLog); + }); + pastedData.selectedObjects.forEach(function(object) { + // refresh the ids so there are no collisions. + if (object.type === SNAKE) { + object.id = newSnake(object.id % snakeColors.length).id; + } else if (object.type === BLOCK) { + object.id = newBlock().id; + } else if (object.type === FRUIT) { + object.id = newFruit().id; + } else if (object.type === POISON_FRUIT) { + object.id = newPoisonFruit().id; + } else throw unreachable(); + level.objects.push(object); + changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); + }); + } else if (paintBrushTileCode === SNAKE) { + var oldSnakeSerialization = serializeObjectState(paintBrushObject); + if (paintBrushObject != null) { + // keep dragging + if (paintBrushObject.locations[0] === location) return; // we just did that + // watch out for self-intersection + var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); + if (selfIntersectionIndex !== -1) { + // truncate from here back + paintBrushObject.locations.splice(selfIntersectionIndex); + } + } - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); + // make sure there's space behind us + paintTileAtLocation(location, SPACE, changeLog); + removeAnyObjectAtLocation(location, changeLog); + if (paintBrushObject == null) { + var thereWereNoSnakes = countSnakes() === 0; + paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); + level.objects.push(paintBrushObject); + if (thereWereNoSnakes) activateAnySnakePlease(); + } else { + // extend le snake + paintBrushObject.locations.unshift(location); + } + changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); + } else if (paintBrushTileCode === BLOCK) { + var objectHere = findObjectAtLocation(location); + if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { + // just start editing this block + paintBrushBlockId = objectHere.id; + } else { + // make a change + // make sure there's space behind us + paintTileAtLocation(location, SPACE, changeLog); + var thisBlock = null; + if (paintBrushBlockId != null) { + thisBlock = findBlockById(paintBrushBlockId); + } + var oldBlockSerialization = serializeObjectState(thisBlock); + if (thisBlock == null) { + // create new block removeAnyObjectAtLocation(location, changeLog); - if (paintBrushObject == null) { - var thereWereNoSnakes = countSnakes() === 0; - paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); - level.objects.push(paintBrushObject); - if (thereWereNoSnakes) activateAnySnakePlease(); - } else { - // extend le snake - paintBrushObject.locations.unshift(location); - } - changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); - } else if (paintBrushTileCode === BLOCK) { - var objectHere = findObjectAtLocation(location); - if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { - // just start editing this block - paintBrushBlockId = objectHere.id; + thisBlock = newBlock(location); + level.objects.push(thisBlock); + paintBrushBlockId = thisBlock.id; + } else { + var existingIndex = thisBlock.locations.indexOf(location); + if (existingIndex !== -1) { + // reclicking part of this object means to delete just part of it. + if (thisBlock.locations.length === 1) { + // goodbye + removeObject(thisBlock, changeLog); + paintBrushBlockId = null; + } else { + thisBlock.locations.splice(existingIndex, 1); + } } else { - // make a change - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - var thisBlock = null; - if (paintBrushBlockId != null) { - thisBlock = findBlockById(paintBrushBlockId); - } - var oldBlockSerialization = serializeObjectState(thisBlock); - if (thisBlock == null) { - // create new block - removeAnyObjectAtLocation(location, changeLog); - thisBlock = newBlock(location); - level.objects.push(thisBlock); - paintBrushBlockId = thisBlock.id; - } else { - var existingIndex = thisBlock.locations.indexOf(location); - if (existingIndex !== -1) { - // reclicking part of this object means to delete just part of it. - if (thisBlock.locations.length === 1) { - // goodbye - removeObject(thisBlock, changeLog); - paintBrushBlockId = null; - } else { - thisBlock.locations.splice(existingIndex, 1); - } - } else { - // add a tile to the block - removeAnyObjectAtLocation(location, changeLog); - thisBlock.locations.push(location); - } - } - changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); - delete blockSupportRenderCache[thisBlock.id]; + // add a tile to the block + removeAnyObjectAtLocation(location, changeLog); + thisBlock.locations.push(location); } - } else if (paintBrushTileCode === FRUIT || paintBrushTileCode === POISON_FRUIT) { - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - var object = paintBrushTileCode == FRUIT ? newFruit(location) : newPoisonFruit(location); - level.objects.push(object); - changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); - } else throw unreachable(); - render(); + } + changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); + delete blockSupportRenderCache[thisBlock.id]; + } + } else if (paintBrushTileCode === FRUIT || paintBrushTileCode === POISON_FRUIT) { + paintTileAtLocation(location, SPACE, changeLog); + removeAnyObjectAtLocation(location, changeLog); + var object = paintBrushTileCode == FRUIT ? newFruit(location) : newPoisonFruit(location); + level.objects.push(object); + changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); + } else throw unreachable(); + render(); } function paintTileAtLocation(location, tileCode, changeLog) { - if (level.map[location] === tileCode) return; - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; + if (level.map[location] === tileCode) return; + changeLog.push(["m", location, level.map[location], tileCode]); + level.map[location] = tileCode; } function pushUndo(undoStuff, changeLog) { - // changeLog = [ - // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], - // // player input for snake 0, dr:-1, dc:0. has no effect on state. - // // "i" is always the first change in normal player movement. - // // if a changeLog does not start with "i", then it is an editor action. - // // animationQueue and freshlyRemovedAnimatedObjects - // // are used for animating re-move. - // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 - // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] - // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] - // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] - // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] - // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. - // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. - // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. - // 10, // the last change is always a declaration of the final width of the map. - // ]; - reduceChangeLog(changeLog); - if (changeLog.length === 0) return; - changeLog.push(level.width); - undoStuff.undoStack.push(changeLog); - undoStuff.redoStack = []; - paradoxes = []; - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; - - undoStuffChanged(undoStuff); + // changeLog = [ + // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], + // // player input for snake 0, dr:-1, dc:0. has no effect on state. + // // "i" is always the first change in normal player movement. + // // if a changeLog does not start with "i", then it is an editor action. + // // animationQueue and freshlyRemovedAnimatedObjects + // // are used for animating re-move. + // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 + // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] + // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] + // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] + // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] + // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. + // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. + // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. + // 10, // the last change is always a declaration of the final width of the map. + // ]; + reduceChangeLog(changeLog); + if (changeLog.length === 0) return; + changeLog.push(level.width); + undoStuff.undoStack.push(changeLog); + undoStuff.redoStack = []; + paradoxes = []; + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; + + undoStuffChanged(undoStuff); } function reduceChangeLog(changeLog) { - for (var i = 0; i < changeLog.length - 1; i++) { - var change = changeLog[i]; - if (change[0] === "i") { - continue; // don't reduce player input - } else if (change[0] === "h") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "h") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "w") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "w") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "w") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "h") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "m") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "m" && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (change[2] === change[3]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === change[0] && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (deepEquals(change[2], change[3])) { - // no change - changeLog.splice(i, 1); - i--; - } - } else throw unreachable(); - } + for (var i = 0; i < changeLog.length - 1; i++) { + var change = changeLog[i]; + if (change[0] === "i") { + continue; // don't reduce player input + } else if (change[0] === "h") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "h") { + // combine + change[2] = otherChange[2]; + changeLog.splice(j, 1); + j--; + continue; + } else if (otherChange[0] === "w") { + continue; // no interaction between height and width + } else break; // no more reduction possible + } + if (change[1] === change[2]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === "w") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "w") { + // combine + change[2] = otherChange[2]; + changeLog.splice(j, 1); + j--; + continue; + } else if (otherChange[0] === "h") { + continue; // no interaction between height and width + } else break; // no more reduction possible + } + if (change[1] === change[2]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === "m") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "m" && otherChange[1] === change[1]) { + // combine + change[3] = otherChange[3]; + changeLog.splice(j, 1); + j--; + } else if (otherChange[0] === "w" || otherChange[0] === "h") { + break; // can't reduce accros resizes + } + } + if (change[2] === change[3]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === change[0] && otherChange[1] === change[1]) { + // combine + change[3] = otherChange[3]; + changeLog.splice(j, 1); + j--; + } else if (otherChange[0] === "w" || otherChange[0] === "h") { + break; // can't reduce accros resizes + } + } + if (deepEquals(change[2], change[3])) { + // no change + changeLog.splice(i, 1); + i--; + } + } else throw unreachable(); + } } function undo(undoStuff) { - if (undoStuff.undoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - undoOneFrame(undoStuff); - undoStuffChanged(undoStuff); + if (undoStuff.undoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + undoOneFrame(undoStuff); + undoStuffChanged(undoStuff); } function reset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.undoStack.length > 0) { - undoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + while (undoStuff.undoStack.length > 0) { + undoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); } function undoOneFrame(undoStuff) { - var doThis = undoStuff.undoStack.pop(); - var redoChangeLog = []; - undoChanges(doThis, redoChangeLog); - if (redoChangeLog.length > 0) { - redoChangeLog.push(level.width); - undoStuff.redoStack.push(redoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; + var doThis = undoStuff.undoStack.pop(); + var redoChangeLog = []; + undoChanges(doThis, redoChangeLog); + if (redoChangeLog.length > 0) { + redoChangeLog.push(level.width); + undoStuff.redoStack.push(redoChangeLog); + } + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; } function redo(undoStuff) { - if (undoStuff.redoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - redoOneFrame(undoStuff); - undoStuffChanged(undoStuff); + if (undoStuff.redoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + redoOneFrame(undoStuff); + undoStuffChanged(undoStuff); } function redoAll(undoStuff) { - if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); - // preserve the level in the url bar. - var hash = "#level=" + currentSerializedLevel; - if (dirtyState === REPLAY_DIRTY) { - // there is a replay to save - hash += "#replay=" + compressSerialization(stringifyReplay()); - } - - var sv = "https://jmdiamond3.github.io/Snakefall-Redesign/SolutionVerification.html" + hash; - copyToClipboard(sv); + if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); + // preserve the level in the url bar. + var hash = "#level=" + currentSerializedLevel; + if (dirtyState === REPLAY_DIRTY) { + // there is a replay to save + hash += "#replay=" + compressSerialization(stringifyReplay()); + } + + var sv = "https://jmdiamond3.github.io/Snakefall-Redesign/SolutionVerification.html" + hash; + copyToClipboard(sv); } function copyToClipboard(text) { var dummy = document.createElement("textarea"); @@ -1462,199 +1462,199 @@ function copyToClipboard(text) { document.body.removeChild(dummy); } function unreset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.redoStack.length > 0) { - redoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + while (undoStuff.redoStack.length > 0) { + redoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); - // don't animate the last frame - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; + // don't animate the last frame + animationQueue = []; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = []; } function redoOneFrame(undoStuff) { - var doThis = undoStuff.redoStack.pop(); - var undoChangeLog = []; - undoChanges(doThis, undoChangeLog); - if (undoChangeLog.length > 0) { - undoChangeLog.push(level.width); - undoStuff.undoStack.push(undoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; + var doThis = undoStuff.redoStack.pop(); + var undoChangeLog = []; + undoChanges(doThis, undoChangeLog); + if (undoChangeLog.length > 0) { + undoChangeLog.push(level.width); + undoStuff.undoStack.push(undoChangeLog); + } + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; } function undoChanges(changes, changeLog) { - var widthContext = changes.pop(); - var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); - for (var i = changes.length - 1; i >= 0; i--) { - var paradoxDescription = undoChange(changes[i]); - if (paradoxDescription != null) paradoxes.push(paradoxDescription); - } - - var lastChange = changes[changes.length - 1]; - if (lastChange[0] === "i") { - // replay animation - animationQueue = lastChange[4]; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = lastChange[5]; - animationStart = new Date().getTime(); - } - - function undoChange(change) { - // note: everything here is going backwards: to -> from - if (change[0] === "i") { - // no state change, but preserve the intention. - changeLog.push(change); - return null; - } else if (change[0] === "h") { - // change height - var fromHeight = change[1]; - var toHeight = change[2]; - if (level.height !== toHeight) return "Impossible"; - setHeight(fromHeight, changeLog); - } else if (change[0] === "w") { - // change width - var fromWidth = change[1]; - var toWidth = change[2]; - if (level.width !== toWidth) return "Impossible"; - setWidth(fromWidth, changeLog); - } else if (change[0] === "m") { - // change map tile - var location = transformLocation(change[1]); - var fromTileCode = change[2]; - var toTileCode = change[3]; - if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; - if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; - paintTileAtLocation(location, fromTileCode, changeLog); - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { - // change object - var type = change[0]; - var id = change[1]; - var fromDead = change[2][0]; - var toDead = change[3][0]; - var fromLocations = change[2][1].map(transformLocation); - var toLocations = change[3][1].map(transformLocation); - if (fromLocations.filter(function (location) { return location >= level.map.length; }).length > 0) { - return "Can't move " + describe(type, id) + " out of bounds"; - } - var object = findObjectOfTypeAndId(type, id); - if (toLocations.length !== 0) { - // should exist at this location - if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; - if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; - if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; - // doit - if (fromLocations.length !== 0) { - var oldState = serializeObjectState(object); - object.locations = fromLocations; - object.dead = fromDead; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - } else { - removeObject(object, changeLog); - } - } else { - // shouldn't exist - if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; - // doit - object = { - type: type, - id: id, - dead: fromDead, - locations: fromLocations, - }; - level.objects.push(object); - changeLog.push([object.type, object.id, [0, []], serializeObjectState(object)]); - } - } else throw unreachable(); - } + var widthContext = changes.pop(); + var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); + for (var i = changes.length - 1; i >= 0; i--) { + var paradoxDescription = undoChange(changes[i]); + if (paradoxDescription != null) paradoxes.push(paradoxDescription); + } + + var lastChange = changes[changes.length - 1]; + if (lastChange[0] === "i") { + // replay animation + animationQueue = lastChange[4]; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = lastChange[5]; + animationStart = new Date().getTime(); + } + + function undoChange(change) { + // note: everything here is going backwards: to -> from + if (change[0] === "i") { + // no state change, but preserve the intention. + changeLog.push(change); + return null; + } else if (change[0] === "h") { + // change height + var fromHeight = change[1]; + var toHeight = change[2]; + if (level.height !== toHeight) return "Impossible"; + setHeight(fromHeight, changeLog); + } else if (change[0] === "w") { + // change width + var fromWidth = change[1]; + var toWidth = change[2]; + if (level.width !== toWidth) return "Impossible"; + setWidth(fromWidth, changeLog); + } else if (change[0] === "m") { + // change map tile + var location = transformLocation(change[1]); + var fromTileCode = change[2]; + var toTileCode = change[3]; + if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; + if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; + paintTileAtLocation(location, fromTileCode, changeLog); + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { + // change object + var type = change[0]; + var id = change[1]; + var fromDead = change[2][0]; + var toDead = change[3][0]; + var fromLocations = change[2][1].map(transformLocation); + var toLocations = change[3][1].map(transformLocation); + if (fromLocations.filter(function(location) { return location >= level.map.length; }).length > 0) { + return "Can't move " + describe(type, id) + " out of bounds"; + } + var object = findObjectOfTypeAndId(type, id); + if (toLocations.length !== 0) { + // should exist at this location + if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; + if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; + if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; + // doit + if (fromLocations.length !== 0) { + var oldState = serializeObjectState(object); + object.locations = fromLocations; + object.dead = fromDead; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + } else { + removeObject(object, changeLog); + } + } else { + // shouldn't exist + if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; + // doit + object = { + type: type, + id: id, + dead: fromDead, + locations: fromLocations, + }; + level.objects.push(object); + changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); + } + } else throw unreachable(); + } } function describe(arg1, arg2) { - // describe(0) -> "Space" - // describe(SNAKE, 0) -> "Snake 0 (Red)" - // describe(object) -> "Snake 0 (Red)" - // describe(BLOCK, 1) -> "Block 1" - // describe(FRUIT) -> "Fruit" - if (typeof arg1 === "number") { - switch (arg1) { - case SPACE: return "Space"; - case WALL: return "a Wall"; - case SPIKE: return "Spikes"; - case EXIT: return "an Exit"; - case PORTAL: return "a Portal"; - case PLATFORM: return "a Platform"; - case WOODPLATFORM: return "a Wooden Platform"; - case ONEWAYWALLU: return "a One Way Wall (facing U)"; - case ONEWAYWALLD: return "a One Way Wall (facing D)"; - case ONEWAYWALLL: return "a One Way Wall (facing L)"; - case ONEWAYWALLR: return "a One Way Wall (facing R)"; - case CLOSEDLIFT: return "a Closed Lift"; - case OPENLIFT: return "an Open Lift"; - case CLOUD: return "a Cloud"; - case BUBBLE: return "a Bubble"; - case LAVA: return "Lava"; - case WATER: return "Water"; - default: throw unreachable(); - } - } - if (arg1 === SNAKE) { - var color = (function () { - switch (snakeColors[arg2 % snakeColors.length]) { - case "#fd0c0b": return " (Red)"; - case "#18d11f": return " (Green)"; - case "#004cff": return " (Blue)"; - case "#fdc122": return " (Yellow)"; - default: throw unreachable(); - } - })(); - return "Snake " + arg2 + color; - } - if (arg1 === BLOCK) { - return "Block " + arg2; - } - if (arg1 === FRUIT) { - return "Fruit"; - } - if (arg1 === POISON_FRUIT) { - return "Poison Fruit"; + // describe(0) -> "Space" + // describe(SNAKE, 0) -> "Snake 0 (Red)" + // describe(object) -> "Snake 0 (Red)" + // describe(BLOCK, 1) -> "Block 1" + // describe(FRUIT) -> "Fruit" + if (typeof arg1 === "number") { + switch (arg1) { + case SPACE: return "Space"; + case WALL: return "a Wall"; + case SPIKE: return "Spikes"; + case EXIT: return "an Exit"; + case PORTAL: return "a Portal"; + case PLATFORM: return "a Platform"; + case WOODPLATFORM: return "a Wooden Platform"; + case ONEWAYWALLU: return "a One Way Wall (facing U)"; + case ONEWAYWALLD: return "a One Way Wall (facing D)"; + case ONEWAYWALLL: return "a One Way Wall (facing L)"; + case ONEWAYWALLR: return "a One Way Wall (facing R)"; + case CLOSEDLIFT: return "a Closed Lift"; + case OPENLIFT: return "an Open Lift"; + case CLOUD: return "a Cloud"; + case BUBBLE: return "a Bubble"; + case LAVA: return "Lava"; + case WATER: return "Water"; + default: throw unreachable(); } - if (typeof arg1 === "object") return describe(arg1.type, arg1.id); - throw unreachable(); + } + if (arg1 === SNAKE) { + var color = (function() { + switch (snakeColors[arg2 % snakeColors.length]) { + case "#fd0c0b": return " (Red)"; + case "#18d11f": return " (Green)"; + case "#004cff": return " (Blue)"; + case "#fdc122": return " (Yellow)"; + default: throw unreachable(); + } + })(); + return "Snake " + arg2 + color; + } + if (arg1 === BLOCK) { + return "Block " + arg2; + } + if (arg1 === FRUIT) { + return "Fruit"; + } + if (arg1 === POISON_FRUIT) { + return "Poison Fruit"; + } + if (typeof arg1 === "object") return describe(arg1.type, arg1.id); + throw unreachable(); } function undoStuffChanged(undoStuff) { - var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; - document.getElementById(undoStuff.spanId).textContent = movesText; - document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; - document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; - - // render paradox display - var uniqueParadoxes = []; - var paradoxCounts = []; - paradoxes.forEach(function (paradoxDescription) { - var index = uniqueParadoxes.indexOf(paradoxDescription); - if (index !== -1) { - paradoxCounts[index] += 1; - } else { - uniqueParadoxes.push(paradoxDescription); - paradoxCounts.push(1); - } - }); - var paradoxDivContent = ""; - uniqueParadoxes.forEach(function (paradox, i) { - if (i > 0) paradoxDivContent += "
    \n"; - if (paradoxCounts[i] > 1) paradoxDivContent += "(" + paradoxCounts[i] + "x) "; - paradoxDivContent += "Time Travel Paradox! " + uniqueParadoxes[i]; - }); - document.getElementById("paradoxDiv").innerHTML = paradoxDivContent; - - updateDirtyState(); - - if (unmoveStuff.redoStack.length === 0) { - document.getElementById("removeButton").classList.remove("click-me"); + var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; + document.getElementById(undoStuff.spanId).textContent = movesText; + document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; + document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; + + // render paradox display + var uniqueParadoxes = []; + var paradoxCounts = []; + paradoxes.forEach(function(paradoxDescription) { + var index = uniqueParadoxes.indexOf(paradoxDescription); + if (index !== -1) { + paradoxCounts[index] += 1; + } else { + uniqueParadoxes.push(paradoxDescription); + paradoxCounts.push(1); } + }); + var paradoxDivContent = ""; + uniqueParadoxes.forEach(function(paradox, i) { + if (i > 0) paradoxDivContent += "
    \n"; + if (paradoxCounts[i] > 1) paradoxDivContent += "(" + paradoxCounts[i] + "x) "; + paradoxDivContent += "Time Travel Paradox! " + uniqueParadoxes[i]; + }); + document.getElementById("paradoxDiv").innerHTML = paradoxDivContent; + + updateDirtyState(); + + if (unmoveStuff.redoStack.length === 0) { + document.getElementById("removeButton").classList.remove("click-me"); + } } var CLEAN_NO_TIMELINES = 0; @@ -1664,70 +1664,70 @@ var EDITOR_DIRTY = 3; var dirtyState = CLEAN_NO_TIMELINES; var editorHasBeenTouched = false; function updateDirtyState() { - if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { - dirtyState = EDITOR_DIRTY; - } else if (unmoveStuff.undoStack.length > 0) { - dirtyState = REPLAY_DIRTY; - } else if (unmoveStuff.redoStack.length > 0) { - dirtyState = CLEAN_WITH_REDO; - } else { - dirtyState = CLEAN_NO_TIMELINES; - } - - var saveLevelButton = document.getElementById("saveLevelButton"); - // the save button clears your timelines - saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; - if (dirtyState >= EDITOR_DIRTY) { - // you should save - saveLevelButton.classList.add("click-me"); - } else { - saveLevelButton.classList.remove("click-me"); - } - - var saveProgressButton = document.getElementById("saveProgressButton"); - // you can't save a replay if your level is dirty - if (dirtyState === CLEAN_WITH_REDO) { - saveProgressButton.textContent = "Forget Progress"; - } else { - saveProgressButton.textContent = "Save Progress"; - } - saveProgressButton.disabled = dirtyState >= EDITOR_DIRTY || dirtyState === CLEAN_NO_TIMELINES; + if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { + dirtyState = EDITOR_DIRTY; + } else if (unmoveStuff.undoStack.length > 0) { + dirtyState = REPLAY_DIRTY; + } else if (unmoveStuff.redoStack.length > 0) { + dirtyState = CLEAN_WITH_REDO; + } else { + dirtyState = CLEAN_NO_TIMELINES; + } + + var saveLevelButton = document.getElementById("saveLevelButton"); + // the save button clears your timelines + saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; + if (dirtyState >= EDITOR_DIRTY) { + // you should save + saveLevelButton.classList.add("click-me"); + } else { + saveLevelButton.classList.remove("click-me"); + } + + var saveProgressButton = document.getElementById("saveProgressButton"); + // you can't save a replay if your level is dirty + if (dirtyState === CLEAN_WITH_REDO) { + saveProgressButton.textContent = "Forget Progress"; + } else { + saveProgressButton.textContent = "Save Progress"; + } + saveProgressButton.disabled = dirtyState >= EDITOR_DIRTY || dirtyState === CLEAN_NO_TIMELINES; } function haveCheatcodesBeenUsed() { - return !unmoveStuff.undoStack.every(function (changeLog) { - // normal movement always starts with "i". - return changeLog[0][0] === "i"; - }); + return !unmoveStuff.undoStack.every(function(changeLog) { + // normal movement always starts with "i". + return changeLog[0][0] === "i"; + }); } var persistentState = { - showEditor: false, - showGrid: false, + showEditor: false, + showGrid: false, }; function savePersistentState() { - localStorage.snakefall = JSON.stringify(persistentState); + localStorage.snakefall = JSON.stringify(persistentState); } function loadPersistentState() { - try { - persistentState = JSON.parse(localStorage.snakefall); - } catch (e) { - } - persistentState.showEditor = !!persistentState.showEditor; - persistentState.showGrid = !!persistentState.showGrid; - showEditorChanged(); + try { + persistentState = JSON.parse(localStorage.snakefall); + } catch (e) { + } + persistentState.showEditor = !!persistentState.showEditor; + persistentState.showGrid = !!persistentState.showGrid; + showEditorChanged(); } var isGravityEnabled = true; function isGravity() { - return isGravityEnabled || !persistentState.showEditor; + return isGravityEnabled || !persistentState.showEditor; } var isCollisionEnabled = true; function isCollision() { - return isCollisionEnabled || !persistentState.showEditor; + return isCollisionEnabled || !persistentState.showEditor; } function isAnyCheatcodeEnabled() { - return persistentState.showEditor && ( - !isGravityEnabled || !isCollisionEnabled - ); + return persistentState.showEditor && ( + !isGravityEnabled || !isCollisionEnabled + ); } var themeName = "Spring"; //Gooby var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle, experimentalColors; @@ -1742,31 +1742,31 @@ var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; var snakeColors2 = ["#f00", "#0f0", "#00f", "#ff0"]; var snakeColors3 = ["#BA145C", "#E91624", "#F75802", "#FEFE28"]; -var fruitColors1 = ["#ff0066", "#ff36a6", "#ff6b1f", "#ff9900", "#ff2600"]; -var fruitColors2 = ["black", "black", "black", "black", "black"]; +var fruitColors1 = ["#ff0066","#ff36a6","#ff6b1f","#ff9900","#ff2600"]; +var fruitColors2 = ["black","black","black","black","black"]; var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spike, support, box, bolt var spikeColors2 = ["gray", "black", "white", "black"]; var spikeColors3 = ["#333", "#333", "#333", "#777"]; var blockColors1 = [ - ["#de5a6d", "#fa65dd", "#c367e3", "#9c62fa", "#625ff0"], - ["#853641", "#963c84", "#753d88", "#5d3a96", "#3a3990"] + ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"], + ["#853641","#963c84","#753d88","#5d3a96","#3a3990"] ]; var blockColors2 = [ ["#999"], ["#999"] ]; var blockColors3 = [ - ["#de7913", "#7d46a0", "#39868b", "#41ccc2", "#ded800"], - ["#8d4d0c", "#532f6a", "#2c686d", "#207973", "#999400"] + ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"], + ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] ]; var blockColors4 = [ ["#150612", "#a52e8b", "#990077", "#d917af", "#4d003c"], - ["#8d4d0c", "#532f6a", "#2c686d", "#207973", "#999400"] + ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] ]; -var fontSize = tileSize * 5; +var fontSize = tileSize*5; var textStyle1 = ["" + fontSize + "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose var textStyle2 = ["" + fontSize + "px Impact", "#5702c6", "#ff0098"]; var textStyle3 = ["" + fontSize + "px Impact", "#BA145C", "#F75802"]; @@ -1778,542 +1778,547 @@ var experimentalColors2 = ["white", "#FEFE28"]; var themeCounter = 0; var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor, textStyle, experimentalColors - //["sky",], - ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], - ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], - ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], - ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] + //["sky",], + ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], + ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], + ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], + ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], + ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], + ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] ]; function showEditorChanged() { - document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; - ["editorDiv", "editorPane"].forEach(function (id) { - document.getElementById(id).style.display = persistentState.showEditor ? "block" : "none"; - }); - document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : "/WASD"; + document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; + ["editorDiv", "editorPane"].forEach(function(id) { + document.getElementById(id).style.display = persistentState.showEditor ? "block" : "none"; + }); + document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : "/WASD"; - render(); + render(); } function move(dr, dc) { - if (!isAlive()) return; - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; - animationStart = new Date().getTime(); - var activeSnake = findActiveSnake(); - var headRowcol = getRowcol(level, activeSnake.locations[0]); - var newRowcol = { r: headRowcol.r + dr, c: headRowcol.c + dc }; - if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; - var newLocation = getLocation(level, newRowcol.r, newRowcol.c); - var changeLog = []; - - // The changeLog for a player movement starts with the input - // when playing normally. - if (!isAnyCheatcodeEnabled()) { - changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); - } - - var ate = false; - var ate_poison = false; - var pushedObjects = []; - - //track ClosedLifts that had objects on them - var occupiedClosedLift = getOccupiedClosedLiftLocations(); - - if (isCollision()) { - var newTile = level.map[newLocation]; - if (newTile === BUBBLE || newTile === CLOUD) - paintTileAtLocation(newLocation, SPACE, changeLog); - else if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile - var otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { + if (!isAlive()) return; + animationQueue = []; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = []; + animationStart = new Date().getTime(); + var activeSnake = findActiveSnake(); + var headRowcol = getRowcol(level, activeSnake.locations[0]); + var newRowcol = {r:headRowcol.r + dr, c:headRowcol.c + dc}; + if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; + var newLocation = getLocation(level, newRowcol.r, newRowcol.c); + var changeLog = []; + + // The changeLog for a player movement starts with the input + // when playing normally. + if (!isAnyCheatcodeEnabled()) { + changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); + } + + var ate = false; + var ate_poison = false; + var pushedObjects = []; + + //track ClosedLifts that had objects on them + var occupiedClosedLift = getOccupiedClosedLiftLocations(); + + if (isCollision()) { + var newTile = level.map[newLocation]; + if (newTile === BUBBLE || newTile === CLOUD) + paintTileAtLocation(newLocation, SPACE, changeLog); + else if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile + var otherObject = findObjectAtLocation(newLocation); + if (otherObject != null) { + if (otherObject === activeSnake) return; // can't push yourself + if (otherObject.type === FRUIT) { + // eat + removeObject(otherObject, changeLog); + ate = true; + } else if (otherObject.type === POISON_FRUIT) { + // eat poison + removeObject(otherObject, changeLog); + ate_poison = true; + } else if (isTileCodeAir(activeSnake, null, newTile, dr, dc)) { + otherObject = findObjectAtLocation(newLocation); + if (otherObject != null) { if (otherObject === activeSnake) return; // can't push yourself - if (otherObject.type === FRUIT) { - // eat - removeObject(otherObject, changeLog); - ate = true; - } else if (otherObject.type === POISON_FRUIT) { - // eat poison - removeObject(otherObject, changeLog); - ate_poison = true; - } else if (isTileCodeAir(activeSnake, null, newTile, dr, dc)) { - otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { - if (otherObject === activeSnake) return; // can't push yourself - // push objects - if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; - } - } else return; // can't go through that tile - } + // push objects + if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; + } + } else return; // can't go through that tile } - - // slither forward - var activeSnakeOldState = serializeObjectState(activeSnake); - var size1 = activeSnake.locations.length === 1; - var slitherAnimations = [ - 70, - [ - // size-1 snakes really do more of a move than a slither - size1 ? MOVE_SNAKE : SLITHER_HEAD, + } + + // slither forward + var activeSnakeOldState = serializeObjectState(activeSnake); + var size1 = activeSnake.locations.length === 1; + var slitherAnimations = [ + 70, + [ + // size-1 snakes really do more of a move than a slither + size1 ? MOVE_SNAKE : SLITHER_HEAD, + activeSnake.id, + dr, + dc, + ] + ]; + activeSnake.locations.unshift(newLocation); + + // drag your tail forward based on what was/wasn't eaten + var times = 1; + if (ate) { times--; } + if (ate_poison) { times++; } + //if we're going to shrink out of existence, prevent it + var snake_length = activeSnake.locations.length-1; + if (times > snake_length) + { + times = snake_length; + activeSnake.dead = true; + //make the snake appear to vanish into non-existence + activeSnake.locations[0] = {r:-99, c:-99}; + } + for (var t = 0; t < times; ++t) { + for(var i = 1; i snake_length) { - times = snake_length; - activeSnake.dead = true; - //make the snake appear to vanish into non-existence - activeSnake.locations[0] = { r: -99, c: -99 }; - } - for (var t = 0; t < times; ++t) { - for (var i = 1; i < activeSnake.locations.length; i++) { - // drag your tail forward - var oldRowcol = getRowcol(level, activeSnake.locations[i + 1]); - newRowcol = getRowcol(level, activeSnake.locations[i]); - if (!size1) { - slitherAnimations.push([ - SLITHER_TAIL, - activeSnake.id, - newRowcol.r - oldRowcol.r, - newRowcol.c - oldRowcol.c, - ]); - } + newRowcol.r - oldRowcol.r, + newRowcol.c - oldRowcol.c, + ]); } - activeSnake.locations.pop(); } - changeLog.push([activeSnake.type, activeSnake.id, activeSnakeOldState, serializeObjectState(activeSnake)]); - - // did you just push your face into a portal? - var portalLocations = getActivePortalLocations(); - var portalActivationLocations = []; - if (portalLocations.indexOf(newLocation) !== -1) { - portalActivationLocations.push(newLocation); + activeSnake.locations.pop(); + } + changeLog.push([activeSnake.type, activeSnake.id, activeSnakeOldState, serializeObjectState(activeSnake)]); + + // did you just push your face into a portal? + var portalLocations = getActivePortalLocations(); + var portalActivationLocations = []; + if (portalLocations.indexOf(newLocation) !== -1) { + portalActivationLocations.push(newLocation); + } + // push everything, too + moveObjects(pushedObjects, dr, dc, portalLocations, portalActivationLocations, changeLog, slitherAnimations); + animationQueue.push(slitherAnimations); + + occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); + + // gravity loop + var stateToAnimationIndex = {}; + if (isGravity()) for (var fallHeight = 1;; fallHeight++) { + var serializedState = serializeObjects(level.objects); + var infiniteLoopStartIndex = stateToAnimationIndex[serializedState]; + if (infiniteLoopStartIndex != null) { + // infinite loop + animationQueue.push([0, [INFINITE_LOOP, animationQueue.length - infiniteLoopStartIndex]]); + break; + } else { + stateToAnimationIndex[serializedState] = animationQueue.length; } - // push everything, too - moveObjects(pushedObjects, dr, dc, portalLocations, portalActivationLocations, changeLog, slitherAnimations); - animationQueue.push(slitherAnimations); - - occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); - - // gravity loop - var stateToAnimationIndex = {}; - if (isGravity()) for (var fallHeight = 1; ; fallHeight++) { - var serializedState = serializeObjects(level.objects); - var infiniteLoopStartIndex = stateToAnimationIndex[serializedState]; - if (infiniteLoopStartIndex != null) { - // infinite loop - animationQueue.push([0, [INFINITE_LOOP, animationQueue.length - infiniteLoopStartIndex]]); - break; - } else { - stateToAnimationIndex[serializedState] = animationQueue.length; - } - // do portals separate from falling logic - if (portalActivationLocations.length === 1) { - var portalAnimations = [500]; - if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { - animationQueue.push(portalAnimations); - } - portalActivationLocations = []; - } - // now do falling logic - var didAnything = false; - var fallingAnimations = [ - 70 / Math.sqrt(fallHeight), - ]; - var exitAnimationQueue = []; - - // check for exit - if (!isUneatenFruit()) { //Gooby - var snakes = getSnakes(); - for (var i = 0; i < snakes.length; i++) { - var snake = snakes[i]; - if (level.map[snake.locations[0]] === EXIT) { - // (one of) you made it! - removeAnimatedObject(snake, changeLog); - exitAnimationQueue.push([ - 200, - [EXIT_SNAKE, snake.id, 0, 0], - ]); - didAnything = true; - } - } - } - - occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); - - // fall - var dyingObjects = []; - var fallingObjects = level.objects.filter(function (object) { - if (object.type === FRUIT || object.type === POISON_FRUIT) return; // can't fall - var theseDyingObjects = []; - if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; - // this object can fall. maybe more will fall with it too. we'll check those separately. - theseDyingObjects.forEach(function (object) { - addIfNotPresent(dyingObjects, object); - }); - return true; - }); - if (dyingObjects.length > 0) { - var anySnakesDied = false; - dyingObjects.forEach(function (object) { - if (object.type === SNAKE) { - // look what you've done - var oldState = serializeObjectState(object); - object.dead = true; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - anySnakesDied = true; - } else if (object.type === BLOCK) { - // a box fell off the world - removeAnimatedObject(object, changeLog); - removeFromArray(fallingObjects, object); - exitAnimationQueue.push([ - 200, - [ - DIE_BLOCK, - object.id, - 0, 0 - ], - ]); - didAnything = true; - } else throw unreachable(); - }); - if (anySnakesDied) break; - } - if (fallingObjects.length > 0) { - moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); - didAnything = true; + // do portals separate from falling logic + if (portalActivationLocations.length === 1) { + var portalAnimations = [500]; + if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { + animationQueue.push(portalAnimations); + } + portalActivationLocations = []; + } + // now do falling logic + var didAnything = false; + var fallingAnimations = [ + 70 / Math.sqrt(fallHeight), + ]; + var exitAnimationQueue = []; + + // check for exit + if (!isUneatenFruit()) { //Gooby + var snakes = getSnakes(); + for (var i = 0; i < snakes.length; i++) { + var snake = snakes[i]; + if (level.map[snake.locations[0]] === EXIT) { + // (one of) you made it! + removeAnimatedObject(snake, changeLog); + exitAnimationQueue.push([ + 200, + [EXIT_SNAKE, snake.id, 0, 0], + ]); + didAnything = true; } + } + } + + occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); - occupiedClosedLift = openLift(occupiedClosedLift, changeLog); - - if (!didAnything) break; - Array.prototype.push.apply(animationQueue, exitAnimationQueue); - if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); + // fall + var dyingObjects = []; + var fallingObjects = level.objects.filter(function(object) { + if (object.type === FRUIT || object.type === POISON_FRUIT) return; // can't fall + var theseDyingObjects = []; + if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; + // this object can fall. maybe more will fall with it too. we'll check those separately. + theseDyingObjects.forEach(function(object) { + addIfNotPresent(dyingObjects, object); + }); + return true; + }); + if (dyingObjects.length > 0) { + var anySnakesDied = false; + dyingObjects.forEach(function(object) { + if (object.type === SNAKE) { + // look what you've done + var oldState = serializeObjectState(object); + object.dead = true; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + anySnakesDied = true; + } else if (object.type === BLOCK) { + // a box fell off the world + removeAnimatedObject(object, changeLog); + removeFromArray(fallingObjects, object); + exitAnimationQueue.push([ + 200, + [ + DIE_BLOCK, + object.id, + 0, 0 + ], + ]); + didAnything = true; + } else throw unreachable(); + }); + if (anySnakesDied) break; } + if (fallingObjects.length > 0) { + moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); + didAnything = true; + } + + occupiedClosedLift = openLift(occupiedClosedLift, changeLog); - pushUndo(unmoveStuff, changeLog); - render(); + if (!didAnything) break; + Array.prototype.push.apply(animationQueue, exitAnimationQueue); + if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); + } + + pushUndo(unmoveStuff, changeLog); + render(); } -function combineOldAndNewLiftOccupations(oldOccupiedClosedLift) { - var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); - var newlyOccupiedClosedLift = getSetSubtract(newOccupiedClosedLift, oldOccupiedClosedLift); - return oldOccupiedClosedLift.concat(newlyOccupiedClosedLift); +function combineOldAndNewLiftOccupations(oldOccupiedClosedLift) +{ + var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); + var newlyOccupiedClosedLift = getSetSubtract(newOccupiedClosedLift, oldOccupiedClosedLift); + return oldOccupiedClosedLift.concat(newlyOccupiedClosedLift); } -function openLift(oldOccupiedClosedLift, changeLog) { - var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); - var nowUnoccupiedClosedLift = getSetSubtract(oldOccupiedClosedLift, newOccupiedClosedLift); - for (var i = 0; i < nowUnoccupiedClosedLift.length; i++) { - paintTileAtLocation(nowUnoccupiedClosedLift[i], OPENLIFT, changeLog); - } - return newOccupiedClosedLift; +function openLift(oldOccupiedClosedLift, changeLog) +{ + var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); + var nowUnoccupiedClosedLift = getSetSubtract(oldOccupiedClosedLift, newOccupiedClosedLift); + for (var i = 0; i < nowUnoccupiedClosedLift.length; i++) { + paintTileAtLocation(nowUnoccupiedClosedLift[i], OPENLIFT, changeLog); + } + return newOccupiedClosedLift; } function getSetSubtract(array1, array2) { - if (array1.length === 0) return []; - return array1.filter(function (x) { return array2.indexOf(x) == -1; }); + if (array1.length === 0) return []; + return array1.filter(function(x) { return array2.indexOf(x) == -1; }); } function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects) { - // pusher can be null (for gravity) - pushedObjects.push(pushedObject); - // find forward locations - var forwardLocations = []; - for (var i = 0; i < pushedObjects.length; i++) { - pushedObject = pushedObjects[i]; - for (var j = 0; j < pushedObject.locations.length; j++) { - var rowcol = getRowcol(level, pushedObject.locations[j]); - var forwardRowcol = { r: rowcol.r + dr, c: rowcol.c + dc }; - if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { - if (dyingObjects == null) { - // can't push things out of bounds - return false; - } else { - // this thing is going to fall out of bounds - addIfNotPresent(dyingObjects, pushedObject); - addIfNotPresent(pushedObjects, pushedObject); - continue; - } - } - var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); - if (dr === 1 && level.map[forwardLocation] === PLATFORM) { - // this platform holds us, unless we're going through it - var neighborLocations; - if (pushedObject.type === SNAKE) { - neighborLocations = []; - if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); - if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); - } else if (pushedObject.type === BLOCK) { - neighborLocations = pushedObject.locations; - } else throw asdf; - if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface - // we slip right past it - } - var yetAnotherObject = findObjectAtLocation(forwardLocation); - if (yetAnotherObject != null) { - if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === POISON_FRUIT) { - // not pushable - return false; - } - if (yetAnotherObject === pusher) { - // indirect pushing ourselves. - // special check for when we're indirectly pushing the tip of our own tail. - if (forwardLocation === pusher.locations[pusher.locations.length - 1]) { - // for some reason this is ok. ------------ THIS IS THE TAIL GLITCH - continue; - } - return false; - } - addIfNotPresent(pushedObjects, yetAnotherObject); - if (level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work - } else - addIfNotPresent(forwardLocations, forwardLocation); + // pusher can be null (for gravity) + pushedObjects.push(pushedObject); + // find forward locations + var forwardLocations = []; + for (var i = 0; i < pushedObjects.length; i++) { + pushedObject = pushedObjects[i]; + for (var j = 0; j < pushedObject.locations.length; j++) { + var rowcol = getRowcol(level, pushedObject.locations[j]); + var forwardRowcol = {r:rowcol.r + dr, c:rowcol.c + dc}; + if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { + if (dyingObjects == null) { + // can't push things out of bounds + return false; + } else { + // this thing is going to fall out of bounds + addIfNotPresent(dyingObjects, pushedObject); + addIfNotPresent(pushedObjects, pushedObject); + continue; + } + } + var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); + if (dr === 1 && level.map[forwardLocation] === PLATFORM) { + // this platform holds us, unless we're going through it + var neighborLocations; + if (pushedObject.type === SNAKE) { + neighborLocations = []; + if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); + if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); + } else if (pushedObject.type === BLOCK) { + neighborLocations = pushedObject.locations; + } else throw asdf; + if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface + // we slip right past it + } + var yetAnotherObject = findObjectAtLocation(forwardLocation); + if (yetAnotherObject != null) { + if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === POISON_FRUIT) { + // not pushable + return false; } + if (yetAnotherObject === pusher) { + // indirect pushing ourselves. + // special check for when we're indirectly pushing the tip of our own tail. + if (forwardLocation === pusher.locations[pusher.locations.length -1]) { + // for some reason this is ok. ------------ THIS IS THE TAIL GLITCH + continue; + } + return false; + } + addIfNotPresent(pushedObjects, yetAnotherObject); + if(level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work + } else + addIfNotPresent(forwardLocations, forwardLocation); } - // check forward locations - for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform, saw no effect but left new code - var forwardLocation = forwardLocations[i]; - // many of these locations can be inside objects, - // but that means the tile must be air, - // and we already know pushing that object. - var tileCode = level.map[forwardLocation]; - var object = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); - if (!isTileCodeAir(pusher, object, tileCode, dr, dc)) { - if (dyingObjects != null) { - if (tileCode === SPIKE) { - // uh... which object was this again? - if (object.type === SNAKE) { - // ouch! - addIfNotPresent(dyingObjects, object); - continue; - } - - } - else if (tileCode === LAVA) { - if (object.type === SNAKE || object.type === BLOCK) { - addIfNotPresent(dyingObjects, object); - continue; - } - } - else if (tileCode === WATER) { - if (object.type === BLOCK) { - addIfNotPresent(dyingObjects, object); - continue; - } - } + } + // check forward locations + for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform, saw no effect but left new code + var forwardLocation = forwardLocations[i]; + // many of these locations can be inside objects, + // but that means the tile must be air, + // and we already know pushing that object. + var tileCode = level.map[forwardLocation]; + var object = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); + if (!isTileCodeAir(pusher, object, tileCode, dr, dc)) { + if (dyingObjects != null) { + if (tileCode === SPIKE) { + // uh... which object was this again? + if (object.type === SNAKE) { + // ouch! + addIfNotPresent(dyingObjects, object); + continue; + } + + } + else if (tileCode === LAVA) { + if (object.type === SNAKE || object.type === BLOCK) { + addIfNotPresent(dyingObjects, object); + continue; + } + } + else if (tileCode === WATER) { + if (object.type === BLOCK) { + addIfNotPresent(dyingObjects, object); + continue; } - // can't push into something solid - return false; } + } + // can't push into something solid + return false; } - // the push is go - return true; + } + // the push is go + return true; } function activateAnySnakePlease() { - var snakes = getSnakes(); - if (snakes.length === 0) return; // nope.avi - activeSnakeId = snakes[0].id; + var snakes = getSnakes(); + if (snakes.length === 0) return; // nope.avi + activeSnakeId = snakes[0].id; } function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations, changeLog, animations) { - objects.forEach(function (object) { - var oldState = serializeObjectState(object); - var oldPortals = getSetIntersection(portalLocations, object.locations); - for (var i = 0; i < object.locations.length; i++) { - object.locations[i] = offsetLocation(object.locations[i], dr, dc); - if (level.map[object.locations[i]] == BUBBLE || level.map[object.locations[i]] == CLOUD) - paintTileAtLocation(object.locations[i], SPACE, changeLog); - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - animations.push([ - "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK - object.id, - dr, - dc, - ]); - - var newPortals = getSetIntersection(portalLocations, object.locations); - var activatingPortals = newPortals.filter(function (portalLocation) { - return oldPortals.indexOf(portalLocation) === -1; - }); - if (activatingPortals.length === 1) { - // exactly one new portal we're touching. activate it - portalActivationLocations.push(activatingPortals[0]); - } - }); -} - -function activatePortal(portalLocations, portalLocation, animations, changeLog) { - var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; - var portalRowcol = getRowcol(level, portalLocation); - var otherPortalRowcol = getRowcol(level, otherPortalLocation); - var delta = { r: otherPortalRowcol.r - portalRowcol.r, c: otherPortalRowcol.c - portalRowcol.c }; - - var object = findObjectAtLocation(portalLocation); - var newLocations = []; + objects.forEach(function(object) { + var oldState = serializeObjectState(object); + var oldPortals = getSetIntersection(portalLocations, object.locations); for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r + delta.r; - var c = rowcol.c + delta.c; - if (!isInBounds(level, r, c)) return false; // out of bounds - newLocations.push(getLocation(level, r, c)); + object.locations[i] = offsetLocation(object.locations[i], dr, dc); + if (level.map[object.locations[i]] == BUBBLE || level.map[object.locations[i]] == CLOUD) + paintTileAtLocation(object.locations[i], SPACE, changeLog); } - - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile - var otherObject = findObjectAtLocation(location); - if (otherObject != null && otherObject !== object) return; // blocked by object + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + animations.push([ + "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK + object.id, + dr, + dc, + ]); + + var newPortals = getSetIntersection(portalLocations, object.locations); + var activatingPortals = newPortals.filter(function(portalLocation) { + return oldPortals.indexOf(portalLocation) === -1; + }); + if (activatingPortals.length === 1) { + // exactly one new portal we're touching. activate it + portalActivationLocations.push(activatingPortals[0]); } + }); +} - // zappo presto! - var oldState = serializeObjectState(object); - object.locations = newLocations; - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (level.map[location] == BUBBLE || level.map[location] == CLOUD) //changed this despite bubble working perfectly without it - paintTileAtLocation(location, SPACE, changeLog); - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); +function activatePortal(portalLocations, portalLocation, animations, changeLog) { + var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; + var portalRowcol = getRowcol(level, portalLocation); + var otherPortalRowcol = getRowcol(level, otherPortalLocation); + var delta = {r:otherPortalRowcol.r - portalRowcol.r, c:otherPortalRowcol.c - portalRowcol.c}; + + var object = findObjectAtLocation(portalLocation); + var newLocations = []; + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r + delta.r; + var c = rowcol.c + delta.c; + if (!isInBounds(level, r, c)) return false; // out of bounds + newLocations.push(getLocation(level, r, c)); + } + + for (var i = 0; i < newLocations.length; i++) { + var location = newLocations[i]; + if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile + var otherObject = findObjectAtLocation(location); + if (otherObject != null && otherObject !== object) return; // blocked by object + } + + // zappo presto! + var oldState = serializeObjectState(object); + object.locations = newLocations; + for (var i = 0; i < newLocations.length; i++) { + var location = newLocations[i]; + if (level.map[location] == BUBBLE || level.map[location] == CLOUD) //changed this despite bubble working perfectly without it + paintTileAtLocation(location, SPACE, changeLog); + } + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); } function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { - switch (tileCode) { - case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; - case WOODPLATFORM: case BUBBLE: return pusher != null; - case PLATFORM: return dr != 1; - case ONEWAYWALLU: return dr != 1; - case ONEWAYWALLD: return dr != -1; - case ONEWAYWALLL: return dc != 1; - case ONEWAYWALLR: return dc != -1; - default: return false; - } + switch (tileCode) + { + case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; + case WOODPLATFORM: case BUBBLE: return pusher != null; + case PLATFORM: return dr != 1; + case ONEWAYWALLU: return dr != 1; + case ONEWAYWALLD: return dr != -1; + case ONEWAYWALLL: return dc != 1; + case ONEWAYWALLR: return dc != -1; + default: return false; + } } function addIfNotPresent(array, element) { - if (array.indexOf(element) !== -1) return; - array.push(element); + if (array.indexOf(element) !== -1) return; + array.push(element); } function removeAnyObjectAtLocation(location, changeLog) { - var object = findObjectAtLocation(location); - if (object != null) removeObject(object, changeLog); + var object = findObjectAtLocation(location); + if (object != null) removeObject(object, changeLog); } function removeAnimatedObject(object, changeLog) { - removeObject(object, changeLog); - freshlyRemovedAnimatedObjects.push(object); + removeObject(object, changeLog); + freshlyRemovedAnimatedObjects.push(object); } function removeObject(object, changeLog) { - removeFromArray(level.objects, object); - changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0, []]]); - if (object.type === SNAKE && object.id === activeSnakeId) { - activateAnySnakePlease(); - } - if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { - // no longer editing an object that doesn't exit - paintBrushBlockId = null; - } - if (object.type === BLOCK) { - delete blockSupportRenderCache[object.id]; - } + removeFromArray(level.objects, object); + changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0,[]]]); + if (object.type === SNAKE && object.id === activeSnakeId) { + activateAnySnakePlease(); + } + if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { + // no longer editing an object that doesn't exit + paintBrushBlockId = null; + } + if (object.type === BLOCK) { + delete blockSupportRenderCache[object.id]; + } } function removeFromArray(array, element) { - var index = array.indexOf(element); - if (index === -1) throw unreachable(); - array.splice(index, 1); + var index = array.indexOf(element); + if (index === -1) throw unreachable(); + array.splice(index, 1); } function findActiveSnake() { - var snakes = getSnakes(); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) return snakes[i]; - } - throw unreachable(); + var snakes = getSnakes(); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) return snakes[i]; + } + throw unreachable(); } function findBlockById(id) { - return findObjectOfTypeAndId(BLOCK, id); + return findObjectOfTypeAndId(BLOCK, id); } function findSnakesOfColor(color) { - return level.objects.filter(function (object) { - if (object.type !== SNAKE) return false; - return object.id % snakeColors.length === color; - }); + return level.objects.filter(function(object) { + if (object.type !== SNAKE) return false; + return object.id % snakeColors.length === color; + }); } function findObjectOfTypeAndId(type, id) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.type === type && object.id === id) return object; - } - return null; + for (var i = 0; i < level.objects.length; i++) { + var object = level.objects[i]; + if (object.type === type && object.id === id) return object; + } + return null; } function findObjectAtLocation(location) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.locations.indexOf(location) !== -1) - return object; - } - return null; + for (var i = 0; i < level.objects.length; i++) { + var object = level.objects[i]; + if (object.locations.indexOf(location) !== -1) + return object; + } + return null; } function isUneatenFruit() { - return getObjectsOfType(FRUIT).length > 0 || getObjectsOfType(POISON_FRUIT).length > 0; + return getObjectsOfType(FRUIT).length > 0 || getObjectsOfType(POISON_FRUIT).length > 0; } function getActivePortalLocations() { - var portalLocations = getPortalLocations(); - if (portalLocations.length !== 2) return []; // nice try - return portalLocations; + var portalLocations = getPortalLocations(); + if (portalLocations.length !== 2) return []; // nice try + return portalLocations; } function getPortalLocations() { - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === PORTAL) result.push(i); - } - return result; + var result = []; + for (var i = 0; i < level.map.length; i++) { + if (level.map[i] === PORTAL) result.push(i); + } + return result; } function countSnakes() { - return getSnakes().length; + return getSnakes().length; } function getSnakes() { - return getObjectsOfType(SNAKE); + return getObjectsOfType(SNAKE); } function getBlocks() { - return getObjectsOfType(BLOCK); + return getObjectsOfType(BLOCK); } -function getOccupiedClosedLiftLocations() { - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === CLOSEDLIFT) { - if (findObjectAtLocation(i)) - result.push(i); - } +function getOccupiedClosedLiftLocations() +{ + var result = []; + for (var i = 0; i < level.map.length; i++) { + if (level.map[i] === CLOSEDLIFT) { + if (findObjectAtLocation(i)) + result.push(i); } - return result; + } + return result; } function getObjectsOfType(type) { - return level.objects.filter(function (object) { - return object.type == type; - }); + return level.objects.filter(function(object) { + return object.type == type; + }); } function isDead() { - if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; - return getSnakes().filter(function (snake) { - return !!snake.dead; - }).length > 0; + if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; + return getSnakes().filter(function(snake) { + return !!snake.dead; + }).length > 0; } function isAlive() { - return countSnakes() > 0 && !isDead(); + return countSnakes() > 0 && !isDead(); } var activeSnakeId = null; @@ -2329,22 +2334,22 @@ var DIE_SNAKE = "ds"; var DIE_BLOCK = "db"; var INFINITE_LOOP = "il"; var animationQueue = [ - // // sequence of disjoint animation groups. - // // each group completes before the next begins. - // [ - // 70, // duration of this animation group - // // multiple things to animate simultaneously - // [ - // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, - // objectId, - // dr, - // dc, - // ], - // [ - // INFINITE_LOOP, - // loopSizeNotIncludingThis, - // ], - // ], + // // sequence of disjoint animation groups. + // // each group completes before the next begins. + // [ + // 70, // duration of this animation group + // // multiple things to animate simultaneously + // [ + // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, + // objectId, + // dr, + // dc, + // ], + // [ + // INFINITE_LOOP, + // loopSizeNotIncludingThis, + // ], + // ], ]; var animationQueueCursor = 0; var animationStart = null; // new Date().getTime() @@ -2354,33 +2359,33 @@ var freshlyRemovedAnimatedObjects = []; // render the support beams for blocks into a temporary buffer, and remember it. // this is due to stencil buffers causing slowdown on some platforms. see #25. var blockSupportRenderCache = { - // id: canvas, - // "0": document.createElement("canvas"), + // id: canvas, + // "0": document.createElement("canvas"), }; function render() { - if (level == null) return; - if (animationQueueCursor < animationQueue.length) { - var animationDuration = animationQueue[animationQueueCursor][0]; - animationProgress = (new Date().getTime() - animationStart) / animationDuration; - if (animationProgress >= 1.0) { - // animation group complete - animationProgress -= 1.0; - animationQueueCursor++; - if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { - var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; - animationQueueCursor -= infiniteLoopSize; - } - animationStart = new Date().getTime(); - } + if (level == null) return; + if (animationQueueCursor < animationQueue.length) { + var animationDuration = animationQueue[animationQueueCursor][0]; + animationProgress = (new Date().getTime() - animationStart) / animationDuration; + if (animationProgress >= 1.0) { + // animation group complete + animationProgress -= 1.0; + animationQueueCursor++; + if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { + var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; + animationQueueCursor -= infiniteLoopSize; + } + animationStart = new Date().getTime(); } - if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; - canvas.width = tileSize * level.width; - canvas.height = tileSize * level.height; - var context = canvas.getContext("2d"); //Gooby - - themeName = themes[themeCounter][0]; - if (themeName != "sky") { + } + if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; + canvas.width = tileSize * level.width; + canvas.height = tileSize * level.height; + var context = canvas.getContext("2d"); //Gooby + + themeName = themes[themeCounter][0]; + if(themeName!="sky"){ background = themes[themeCounter][1]; material = themes[themeCounter][2]; surface = themes[themeCounter][3]; @@ -2391,806 +2396,786 @@ function render() { fruitColors = themes[themeCounter][8]; textStyle = themes[themeCounter][10]; experimentalColors = themes[themeCounter][11]; - - if (background.substr(0, 1) == "#") { + + if(background.substr(0,1) == "#") { context.fillStyle = background; context.fillRect(0, 0, canvas.width, canvas.height); } - else { - for (var i = 0; i < level.width; i++) { //checkerboard background - for (var j = 0; j < level.height; j++) { - var bgColor1 = background.substr(0, background.indexOf('*')); - var bgColor2 = background.substr(background.indexOf('*') + 2, background.length); - var shade = (j + 1) * .03 + .5; - if ((i + j) % 2 == 0) context.fillStyle = bgColor1 + ", " + shade + ")"; + else{ + for(var i = 0; i maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var image = blockSupportRenderCache[object.id]; + if (image == null) { + // render the support beams to a buffer + blockSupportRenderCache[object.id] = image = document.createElement("canvas"); + image.width = (maxC - minC + 1) * tileSize; + image.height = (maxR - minR + 1) * tileSize; + var bufferContext = image.getContext("2d"); + // Make a stencil that excludes the insides of blocks. + // Then when we render the support beams, we won't see the supports inside the block itself. + bufferContext.beginPath(); + // Draw a path around the whole screen in the opposite direction as the rectangle paths below. + // This means that the below rectangles will be removing area from the greater rectangle. + bufferContext.rect(image.width, 0, -image.width, image.height); + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r - minR; + var c = rowcol.c - minC; + bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); + } + bufferContext.clip(); + for (var i = 0; i < object.locations.length - 1; i++) { + var rowcol1 = getRowcol(level, object.locations[i]); + rowcol1.r -= minR; + rowcol1.c -= minC; + var rowcol2 = getRowcol(level, object.locations[i + 1]); + rowcol2.r -= minR; + rowcol2.c -= minC; + var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; + drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); + drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); + } + } + var r = minR + animationDisplacementRowcol.r; + var c = minC + animationDisplacementRowcol.c; + context.drawImage(image, c * tileSize, r * tileSize); + }); + + if(!cs) { + // terrain + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + var tileCode = level.map[location]; + drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids } - } else if (paintBrushTileCode === "select") { - getSelectedLocations().forEach(function (location) { - var rowcol = getRowcol(level, location); - drawRect(rowcol.r, rowcol.c, "rgba(128, 128, 128, 0.3)"); - }); + } } - } - - // serialize - if (!isDead()) { - var serialization = stringifyLevel(level); - document.getElementById("serializationTextarea").value = serialization; - var link = location.href.substring(0, location.href.length - location.hash.length); - link += "#level=" + compressSerialization(serialization); - document.getElementById("shareLinkTextbox").value = link; - } - - // throw this in there somewhere - document.getElementById("showGridButton").textContent = (persistentState.showGrid ? "Hide" : "Show") + " Grid"; - if (animationProgress < 1.0) requestAnimationFrame(render); - return; // this is the end of the function proper - - function renderLevel(onlyTheseObjects) { - var objects = level.objects; - if (onlyTheseObjects != null) { - objects = onlyTheseObjects; - } else { - objects = level.objects.concat(freshlyRemovedAnimatedObjects.filter(function (object) { - // the object needs to have a future removal animation, or else, it's gone already. - return hasFutureRemoveAnimation(object); - })); + for(var i = 0; i maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var image = blockSupportRenderCache[object.id]; - if (image == null) { - // render the support beams to a buffer - blockSupportRenderCache[object.id] = image = document.createElement("canvas"); - image.width = (maxC - minC + 1) * tileSize; - image.height = (maxR - minR + 1) * tileSize; - var bufferContext = image.getContext("2d"); - // Make a stencil that excludes the insides of blocks. - // Then when we render the support beams, we won't see the supports inside the block itself. - bufferContext.beginPath(); - // Draw a path around the whole screen in the opposite direction as the rectangle paths below. - // This means that the below rectangles will be removing area from the greater rectangle. - bufferContext.rect(image.width, 0, -image.width, image.height); - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r - minR; - var c = rowcol.c - minC; - bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); - } - bufferContext.clip(); - for (var i = 0; i < object.locations.length - 1; i++) { - var rowcol1 = getRowcol(level, object.locations[i]); - rowcol1.r -= minR; - rowcol1.c -= minC; - var rowcol2 = getRowcol(level, object.locations[i + 1]); - rowcol2.r -= minR; - rowcol2.c -= minC; - var cornerRowcol = { r: rowcol1.r, c: rowcol2.c }; - drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - } - } - var r = minR + animationDisplacementRowcol.r; - var c = minC + animationDisplacementRowcol.c; - context.drawImage(image, c * tileSize, r * tileSize); - }); - if (!cs) { - // terrain - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - var tileCode = level.map[location]; - drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids - } - } - } - - for (var i = 0; i < objects.length; i++) { - var object = objects[i]; - if (object.type === SNAKE || object.type === BLOCK) drawObject(object); //draws snakes and blocks - } - - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - location = getLocation(level, r, c); - tileCode = level.map[location]; - if (tileCode === WALL) drawTile(tileCode, r, c, level, location, false); //draws only walls - } - } - } - - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - location = getLocation(level, r, c); - tileCode = level.map[location]; - if (tileCode === CLOUD || tileCode === LAVA || tileCode === WATER) drawTile(tileCode, r, c, level, location, false); //draws only clouds - } - } + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + location = getLocation(level, r, c); + tileCode = level.map[location]; + if(tileCode === WALL) drawTile(tileCode, r, c, level, location, false); //draws only walls } + } + } - for (var i = 0; i < objects.length; i++) { - var object = objects[i]; - if (object.type === FRUIT || object.type === POISON_FRUIT) drawObject(object); //draws fruit + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + location = getLocation(level, r, c); + tileCode = level.map[location]; + if(tileCode === CLOUD || tileCode === LAVA || tileCode === WATER) drawTile(tileCode, r, c, level, location, false); //draws only clouds } + } } - // banners - if (countSnakes() === 0 && !cs) { - context.fillStyle = textStyle[1]; - context.font = textStyle[0]; - context.shadowOffsetX = 5; - context.shadowOffsetY = 5; - context.shadowColor = "rgba(0,0,0,0.5)"; - context.shadowBlur = 4; - var textString = "WIN"; - var textWidth = context.measureText(textString).width; - context.fillText(textString, (canvas.width / 2) - (textWidth / 2), canvas.height / 2); - checkResult = true; - } - if (isDead()) { - context.fillStyle = textStyle[2]; - context.font = textStyle[0]; - context.shadowOffsetX = 5; - context.shadowOffsetY = 5; - context.shadowColor = "rgba(0,0,0,0.5)"; - context.shadowBlur = 4; - textString = "LOSE"; - textWidth = context.measureText(textString).width; - context.fillText(textString, (canvas.width / 2) - (textWidth / 2), canvas.height / 2); - checkResult = false; + for(var i = 0; i 0.5 ? d / (2 - max - min) : d / (max + min); - switch (max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - h /= 6; - } - - s = s * 100; - s = Math.round(s); - l = l * 100 * 1.2; - l = Math.round(l); - h = Math.round(360*h); - - return 'hsl(' + h + ', ' + s + '%, ' + l + '%)'; + function getAdjacentTiles() { + return [ + [getTile(r - 1, c - 1), + getTile(r - 1, c + 0), + getTile(r - 1, c + 1)], + [getTile(r + 0, c - 1), + null, + getTile(r + 0, c + 1)], + [getTile(r + 1, c - 1), + getTile(r + 1, c + 0), + getTile(r + 1, c + 1)], + ]; } - - function drawObject(object) { - switch (object.type) { - case SNAKE: - var falling = false; - var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); - if (animationDisplacementRowcol.r != 0) falling = true; - var lastRowcol = null - var nextRowcol = null - var color = snakeColors[object.id % snakeColors.length]; - var colorIndex = object.id % snakeColors.length; - //var altColor = getTintedColor(color, 30); - var altColor = lighten(color); - if (themeName === "Classic") altColor = color; - var headRowcol; - var orientation = 10; - for (var i = 0; i < object.locations.length; i++) { - var animation; - var rowcol; - if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward - rowcol = getRowcol(level, object.locations[i]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else if (i === object.locations.length) { - // animated tail? - if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { - // animate tail slithering to catch up - rowcol = getRowcol(level, object.locations[i - 1]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else { - // no animated tail needed - break; - } - } else rowcol = getRowcol(level, object.locations[i]); - - lastRowcol = getRowcol(level, object.locations[i - 1]); //closer to head - nextRowcol = getRowcol(level, object.locations[i + 1]); //closer to tail - var rc = rowcol; - var lrc = lastRowcol; - var nrc = nextRowcol; - - if (object.dead) { //if snake dies after moving left or right, head is positioned down - rowcol.r += .5; - lastRowcol.r += .5; - nextRowcol.r += .5; - falling = true; - } - rowcol.r += animationDisplacementRowcol.r; - rowcol.c += animationDisplacementRowcol.c; - lastRowcol.r += animationDisplacementRowcol.r; - lastRowcol.c += animationDisplacementRowcol.c; - nextRowcol.r += animationDisplacementRowcol.r; - nextRowcol.c += animationDisplacementRowcol.c; - - var cx = rowcol.c * tileSize; - var cy = rowcol.r * tileSize; - - if (i === 0) { - context.fillStyle = color; - headRowcol = rowcol; - - //determines orientation of face - if (!falling) nextRowcol = getRowcol(level, object.locations[1]); - if (nextRowcol.r < rowcol.r) { //last move down - roundRect(context, cx, cy, tileSize, tileSize, { bl: 10, br: 10 }, true, false); //draw head - if (colorIndex === 0) orientation = 2; - else if (colorIndex === 1) orientation = 6; - else if (colorIndex === 2) orientation = 3; - else if (colorIndex === 3) orientation = 5; - } - else if (nextRowcol.r > rowcol.r) { //last move up - roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); //draw head - if (colorIndex === 0) orientation = 0; - else if (colorIndex === 1) orientation = 4; - else if (colorIndex === 2) orientation = 1; - else if (colorIndex === 3) orientation = 7; - } - else if (nextRowcol.c < rowcol.c) { //last move right - roundRect(context, cx, cy, tileSize, tileSize, { tr: 10, br: 10 }, true, false); //draw head - if (colorIndex === 0) orientation = 1; - else if (colorIndex === 1) orientation = 5; - else if (colorIndex === 2) orientation = 2; - else if (colorIndex === 3) orientation = 4; - } - else if (nextRowcol.c > rowcol.c) { //last move left - roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); //draw head - if (colorIndex === 0) orientation = 3; - else if (colorIndex === 1) orientation = 7; - else if (colorIndex === 2) orientation = 0; - else if (colorIndex === 3) orientation = 6; - } - else { - roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); //draw head - orientation = 10; - } - } else { - if (i % 2 == 0) context.fillStyle = color; - else context.fillStyle = altColor; - - if (i === object.locations.length - 1) { - if (lastRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); } - else if (lastRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10, br: 10 }, true, false); } - else if (lastRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10, br: 10 }, true, false); } - else if (lastRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); } - } - else if (i != object.locations.length - 1 && i != object.locations.length) { - if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10 }, true, false); } - else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10 }, true, false); } - else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { br: 10 }, true, false); } - else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10 }, true, false); } - - else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10 }, true, false); } - else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10 }, true, false); } - else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { br: 10 }, true, false); } - else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10 }, true, false); } - - else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, 0, true, false); } - } - else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); - } + function getTile(r, c) { + if (!isInBounds(level, r, c)) return null; + return level.map[getLocation(level, r, c)]; + } + } + +function getTintedColor(color, v) { + if (color.length >6) { color= color.substring(1,color.length)} + var rgb = parseInt(color, 16); + var r = Math.abs(((rgb >> 16) & 0xFF)+v); if (r>255) r=r-(r-255); + var g = Math.abs(((rgb >> 8) & 0xFF)+v); if (g>255) g=g-(g-255); + var b = Math.abs((rgb & 0xFF)+v); if (b>255) b=b-(b-255); + r = Number(r < 0 || isNaN(r)) ? 0 : ((r > 255) ? 255 : r).toString(16); + if (r.length == 1) r = '0' + r; + g = Number(g < 0 || isNaN(g)) ? 0 : ((g > 255) ? 255 : g).toString(16); + if (g.length == 1) g = '0' + g; + b = Number(b < 0 || isNaN(b)) ? 0 : ((b > 255) ? 255 : b).toString(16); + if (b.length == 1) b = '0' + b; + return "#" + r + g + b; +} + + function drawObject(object) { + switch (object.type) { + case SNAKE: + var falling = false; + var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); + if (animationDisplacementRowcol.r != 0) falling = true; + var lastRowcol = null + var nextRowcol = null + var color = snakeColors[object.id % snakeColors.length]; + var colorIndex = object.id % snakeColors.length; + var altColor = getTintedColor(color, 50); + if(themeName==="Classic") altColor = color; + var headRowcol; + var orientation = 10; + for (var i = 0; i < object.locations.length; i++) { + var animation; + var rowcol; + if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward + rowcol = getRowcol(level, object.locations[i]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else if (i === object.locations.length) { + // animated tail? + if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { + // animate tail slithering to catch up + rowcol = getRowcol(level, object.locations[i-1]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else { + // no animated tail needed + break; + } + } else rowcol = getRowcol(level, object.locations[i]); + + lastRowcol = getRowcol(level, object.locations[i-1]); //closer to head + nextRowcol = getRowcol(level, object.locations[i+1]); //closer to tail + var rc = rowcol; + var lrc = lastRowcol; + var nrc = nextRowcol; + + if (object.dead) { //if snake dies after moving left or right, head is positioned down + rowcol.r += .5; + lastRowcol.r += .5; + nextRowcol.r += .5; + falling = true; + } + rowcol.r += animationDisplacementRowcol.r; + rowcol.c += animationDisplacementRowcol.c; + lastRowcol.r += animationDisplacementRowcol.r; + lastRowcol.c += animationDisplacementRowcol.c; + nextRowcol.r += animationDisplacementRowcol.r; + nextRowcol.c += animationDisplacementRowcol.c; + + var cx = rowcol.c * tileSize; + var cy = rowcol.r * tileSize; + + if (i === 0) { + context.fillStyle = color; + headRowcol = rowcol; + + //determines orientation of face + if(!falling) nextRowcol = getRowcol(level, object.locations[1]); + if (nextRowcol.r < rowcol.r) { //last move down + roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false); //draw head + if(colorIndex === 0) orientation = 2; + else if(colorIndex === 1) orientation = 6; + else if(colorIndex === 2) orientation = 3; + else if(colorIndex === 3) orientation = 5; + } + else if (nextRowcol.r > rowcol.r) { //last move up + roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false); //draw head + if(colorIndex === 0) orientation = 0; + else if(colorIndex === 1) orientation = 4; + else if(colorIndex === 2) orientation = 1; + else if(colorIndex === 3) orientation = 7; + } + else if (nextRowcol.c < rowcol.c) { //last move right + roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false); //draw head + if(colorIndex === 0) orientation = 1; + else if(colorIndex === 1) orientation = 5; + else if(colorIndex === 2) orientation = 2; + else if(colorIndex === 3) orientation = 4; + } + else if (nextRowcol.c > rowcol.c) { //last move left + roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false); //draw head + if(colorIndex === 0) orientation = 3; + else if(colorIndex === 1) orientation = 7; + else if(colorIndex === 2) orientation = 0; + else if(colorIndex === 3) orientation = 6; + } + else { + roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); //draw head + orientation = 10; + } + } else { + if(i % 2 == 0) context.fillStyle = color; + else context.fillStyle = altColor; + + if (i === object.locations.length-1) { + if(lastRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false);} + else if(lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false);} + else if(lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false);} + else if(lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false);} } - drawFace(object.id, headRowcol.c, headRowcol.r, orientation); - break; - case BLOCK: - drawBlock(object); - break; - case FRUIT: - case POISON_FRUIT: - var is_poison = object.type == POISON_FRUIT; - rowcol = getRowcol(level, object.locations[0]); - var c = rowcol.c; - var r = rowcol.r; - var startC = c * tileSize + tileSize / 2; - var startR = r * tileSize + tileSize * .2; - var resize = tileSize * 1.7; - var color = fruitColors[object.id % fruitColors.length]; - var stemColor = themes[themeCounter][9] - if (themeName === "Classic") color = "#f0f"; - if (is_poison) { color = "#556815"; stemColor = "black"; } - context.fillStyle = color; - if (themeName != "Classic") { - if (surface == "rainbow") { - context.fillStyle = "black"; - context.lineWidth = tileSize / 8; - context.strokeStyle = "white"; - resize = tileSize * 1.4; - } - //context.fillStyle = "#ff6b45"; - context.beginPath(); - context.moveTo(startC, startR); - context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC - resize * .25, startR - resize * .1, startC - resize * .3, startR + resize * .05); - context.bezierCurveTo(startC - resize * .35, startR + resize * .15, startC - resize * .3, startR + resize * .6, startC, startR + resize * .5); - context.bezierCurveTo(startC + resize * .3, startR + resize * .6, startC + resize * .35, startR + resize * .15, startC + resize * .3, startR + resize * .05); - context.bezierCurveTo(startC + resize * .25, startR - resize * .05, startC + resize * .1, startR - resize * .1, startC, startR); - context.closePath(); - context.fill(); - if (surface == "rainbow") context.stroke(); - - context.beginPath(); - context.moveTo(startC, startR); - context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC, startR - resize * .1, startC - resize * .1, startR - resize * .15); - context.bezierCurveTo(startC, startR - resize * .1, startC + resize * .05, startR - resize * .1, startC, startR); - context.fillStyle = stemColor; - context.fill(); + else if (i != object.locations.length-1 && i != object.locations.length) { + if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} + else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} + else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} + else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} + + else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} + else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} + else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} + else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} + + else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, 0, true, false);} } - else drawCircle(rowcol.r, rowcol.c, 1, color); - break; - default: throw unreachable(); - } - } - - function drawPlatform(r, c, adjacentTiles) { - newPlatform(r, c, isPlatform); - - function isPlatform(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === PLATFORM; + else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); + } } + drawFace(object.id, headRowcol.c, headRowcol.r, orientation); + break; + case BLOCK: + drawBlock(object); + break; + case FRUIT: + case POISON_FRUIT: + var is_poison = object.type == POISON_FRUIT; + rowcol = getRowcol(level, object.locations[0]); + var c = rowcol.c; + var r = rowcol.r; + var startC = c*tileSize+tileSize/2; + var startR = r*tileSize+tileSize*.2; + var resize = tileSize * 1.7; + var color = fruitColors[object.id % fruitColors.length]; + var stemColor = themes[themeCounter][9] + if (is_poison) { color = "#556815"; stemColor = "black";} //placeholder effect + context.fillStyle = color; + if(themeName != "Classic"){ + if(surface == "rainbow") { + context.fillStyle = "black"; + context.lineWidth = tileSize/8; + context.strokeStyle = "white"; + resize = tileSize * 1.4; + } + //context.fillStyle = "#ff6b45"; + context.beginPath(); + context.moveTo(startC, startR); + context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC-resize*.25, startR-resize*.1, startC-resize*.3, startR+resize*.05); + context.bezierCurveTo(startC-resize*.35, startR+resize*.15, startC-resize*.3, startR+resize*.6, startC, startR+resize*.5); + context.bezierCurveTo(startC+resize*.3, startR+resize*.6, startC+resize*.35, startR+resize*.15, startC+resize*.3, startR+resize*.05); + context.bezierCurveTo(startC+resize*.25, startR-resize*.05, startC+resize*.1, startR-resize*.1, startC, startR); + context.closePath(); + context.fill(); + if(surface == "rainbow") context.stroke(); - /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*1, r*tileSize); - context.lineTo(c*tileSize, r*tileSize); - context.closePath(); - context.rect(c*tileSize, r*tileSize+tileSize*.2857, tileSize, tileSize*.1429);*/ - - /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.25, r*tileSize+tileSize*.2, c*tileSize+tileSize*.25, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.75, r*tileSize+tileSize*.2, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo((c+1)*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize);*/ - - /*context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.arc((c + 3/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.arc((c + 1/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.lineTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize, r*tileSize);*/ - - //context.closePath(); - //context.fillStyle = "#000066"; - //ontext.fill(); - //context.stroke(); - } - - function newPlatform(r, c, isOccupied) { - - var x1 = .05; - var x2 = .05; - if (isOccupied(-1, 0)) x1 = 0; - if (isOccupied(1, 0)) x2 = 0; - - var platformColors = ["#ffcccc", "#ffe0cc", "#ffffcc", "#e6ffe6", "#e6e6ff"]; - for (var i = 0; i < 5; i++) { - var j = i - 1; - if (j < 0) j = 0; context.beginPath(); - context.moveTo(c * tileSize + tileSize * (i * x1), r * tileSize + tileSize * (.05 + (.1 * i) - (j * .02))); - context.strokeStyle = platformColors[i]; - context.lineWidth = tileSize * (.1 - (i * .02)); - context.lineTo(c * tileSize + tileSize * (1 - (i * x2)), r * tileSize + tileSize * (.05 + (.1 * i) - (j * .02))); - context.stroke(); + context.moveTo(startC,startR); + context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); + context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); + context.fillStyle = stemColor; + context.fill(); } + else drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); + break; + default: throw unreachable(); } - - function drawOneWayWall(fillStyle, r, c, dr, dc) { - context.lineWidth = 2; - context.strokeStyle = "#333"; - context.beginPath(); - - if (dr == -1) { - context.moveTo(c * tileSize, r * tileSize + tileSize / 2); - context.lineTo(c * tileSize + tileSize / 4, r * tileSize + tileSize / 4); - context.stroke(); - context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + tileSize / 4); - context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize / 2); - } - else if (dr == 1) { - context.moveTo(c * tileSize, r * tileSize + tileSize / 2); - context.lineTo(c * tileSize + tileSize / 4, r * tileSize + 3 * tileSize / 4); - context.stroke(); - context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + 3 * tileSize / 4); - context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize / 2); - } - else if (dc == -1) { - context.moveTo(c * tileSize + tileSize / 2, r * tileSize); - context.lineTo(c * tileSize + tileSize / 4, r * tileSize + tileSize / 4); - context.stroke(); - context.moveTo(c * tileSize + tileSize / 4, r * tileSize + 3 * tileSize / 4); - context.lineTo(c * tileSize + tileSize / 2, r * tileSize + tileSize); - } - else if (dc == 1) { - context.moveTo(c * tileSize + tileSize / 2, r * tileSize); - context.lineTo(c * tileSize + 3 * tileSize / 4, r * tileSize + tileSize / 4); - context.stroke(); - context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + 3 * tileSize / 4); - context.lineTo(c * tileSize + tileSize / 2, r * tileSize + tileSize); - } - - context.stroke(); - context.lineWidth = 0; - - context.fillStyle = fillStyle; - if (dr == -1) roundRect(context, c * tileSize - tileSize / 15, r * tileSize - tileSize / 15, tileSize + 2 * tileSize / 15, tileSize / 4 + 2 * tileSize / 15, 2, true, false); - else if (dr == 1) roundRect(context, c * tileSize - tileSize / 15, (r + 1) * tileSize - tileSize / 15 - tileSize / 4, tileSize + 2 * tileSize / 15, tileSize / 4 + 2 * tileSize / 15, 2, true, false); - else if (dc == -1) roundRect(context, c * tileSize - tileSize / 15, r * tileSize - tileSize / 15, tileSize / 4 + 2 * tileSize / 15, tileSize + 2 * tileSize / 15, 2, true, false); - else if (dc == 1) roundRect(context, (c + 1) * tileSize - tileSize / 15 - tileSize / 4, r * tileSize - tileSize / 15, tileSize / 4 + 2 * tileSize / 15, tileSize + 2 * tileSize / 15, 2, true, false); + } + +function drawPlatform(r, c, adjacentTiles) { + newPlatform(r, c, isPlatform); + + function isPlatform(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === PLATFORM; } - - function drawBubble(r, c) { - bubbleX = c * tileSize; - var grd = context.createRadialGradient(bubbleX, r * tileSize, 0, bubbleX, r * tileSize, tileSize); - grd.addColorStop(0, "rgba(255,255,255,.9)"); - grd.addColorStop(1, "rgba(255,255,255,.2)"); - context.fillStyle = grd; - context.lineWidth = .5; - context.strokeStyle = "rgba(200,200,200,.2)"; - + + /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*1, r*tileSize); + context.lineTo(c*tileSize, r*tileSize); + context.closePath(); + context.rect(c*tileSize, r*tileSize+tileSize*.2857, tileSize, tileSize*.1429);*/ + + /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.25, r*tileSize+tileSize*.2, c*tileSize+tileSize*.25, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.75, r*tileSize+tileSize*.2, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.lineTo((c+1)*tileSize, r*tileSize); + context.lineTo(c*tileSize, r*tileSize);*/ + + /*context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.arc((c + 3/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.arc((c + 1/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.lineTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize+tileSize, r*tileSize);*/ + + //context.closePath(); + //context.fillStyle = "#000066"; + //ontext.fill(); + //context.stroke(); +} + +function newPlatform(r, c, isOccupied){ + + var x1 = .05; + var x2 = .05; + if(isOccupied(-1,0)) x1 = 0; + if(isOccupied(1,0)) x2 = 0; + + var platformColors = ["#ffcccc", "#ffe0cc", "#ffffcc", "#e6ffe6", "#e6e6ff"]; + for(var i = 0; i<5; i++){ + var j = i-1; + if(j<0) j = 0; context.beginPath(); - context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, tileSize / 2, 0, 2 * Math.PI); - context.fill(); + context.moveTo(c*tileSize+tileSize*(i*x1), r*tileSize+tileSize*(.05 + (.1 * i) - (j * .02))); + context.strokeStyle = platformColors[i]; + context.lineWidth = tileSize*(.1-(i*.02)); + context.lineTo(c*tileSize+tileSize*(1-(i*x2)), r*tileSize+tileSize*(.05 + (.1 * i) - (j * .02))); context.stroke(); } - - function drawLiquid(r, c, type, adjacentTiles) { - newLiquid(r, c, type, isSameLiquid); - - function isSameLiquid(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === type; - } +} + + function drawOneWayWall(fillStyle, r, c, dr, dc) { + context.lineWidth = 2; + context.strokeStyle = "#333"; + context.beginPath(); + + if (dr == -1) { + context.moveTo(c * tileSize, r * tileSize + tileSize/2); + context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); + context.stroke(); + context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); + context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); + } + else if (dr == 1) { + context.moveTo(c * tileSize, r * tileSize + tileSize/2); + context.lineTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); + context.stroke(); + context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); + context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); + } + else if (dc == -1) { + context.moveTo(c * tileSize + tileSize/2, r * tileSize); + context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); + context.stroke(); + context.moveTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); + context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); + } + else if (dc == 1) { + context.moveTo(c * tileSize + tileSize/2, r * tileSize); + context.lineTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); + context.stroke(); + context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); + context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); + } + + context.stroke(); + context.lineWidth = 0; + + context.fillStyle = fillStyle; + if (dr == -1) roundRect(context, c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15, 2, true, false); + else if (dr == 1) roundRect(context, c * tileSize - tileSize/15, (r + 1) * tileSize - tileSize/15 - tileSize/4, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15, 2, true, false); + else if (dc == -1) roundRect(context, c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15, 2, true, false); + else if (dc == 1) roundRect(context, (c + 1) * tileSize - tileSize/15 - tileSize/4, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15, 2, true, false); + } + + function drawBubble(r, c) { + bubbleX = c*tileSize; + var grd = context.createRadialGradient(bubbleX, r*tileSize, 0, bubbleX, r*tileSize, tileSize); + grd.addColorStop(0, "rgba(255,255,255,.9)"); + grd.addColorStop(1, "rgba(255,255,255,.2)"); + context.fillStyle = grd; + context.lineWidth = .5; + context.strokeStyle = "rgba(200,200,200,.2)"; + + context.beginPath(); + context.arc(c*tileSize+tileSize*.5, r*tileSize+tileSize*.5, tileSize/2, 0, 2*Math.PI); + context.fill(); + context.stroke(); + } + +function drawLiquid(r, c, type, adjacentTiles) { + newLiquid(r, c, type, isSameLiquid); + + function isSameLiquid(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === type; + } +} + +function newLiquid(r, c, type, isOccupied){ + context.save(); + var tubColor; + if(type == LAVA) { + context.fillStyle = "#ffbf00"; + context.strokeStyle = "red"; + tubColor = "black"; + } + else { + context.fillStyle = "#1a8cff"; + context.strokeStyle = "#80ffe5"; + tubColor = "white"; } - - function newLiquid(r, c, type, isOccupied) { - context.save(); - var tubColor; - if (type == LAVA) { - context.fillStyle = "#ffbf00"; - context.strokeStyle = "red"; - tubColor = "black"; - } - else { - context.fillStyle = "#1a8cff"; - context.strokeStyle = "#80ffe5"; - tubColor = "white"; - } - roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 0, true, false); - - context.lineWidth = 3; - context.beginPath(); - context.moveTo(c * tileSize, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .1, c * tileSize + tileSize / 3, r * tileSize + tileSize * .1, c * tileSize + tileSize / 2, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .3, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .3, c * tileSize + tileSize, r * tileSize + tileSize * .2); - context.moveTo(c * tileSize, r * tileSize + tileSize * .4); - context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .3, c * tileSize + tileSize / 3, r * tileSize + tileSize * .3, c * tileSize + tileSize / 2, r * tileSize + tileSize * .4); - context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .5, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .5, c * tileSize + tileSize, r * tileSize + tileSize * .4); - context.moveTo(c * tileSize, r * tileSize + tileSize * .6); - context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .5, c * tileSize + tileSize / 3, r * tileSize + tileSize * .5, c * tileSize + tileSize / 2, r * tileSize + tileSize * .6); - context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .7, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .7, c * tileSize + tileSize, r * tileSize + tileSize * .6); - context.moveTo(c * tileSize, r * tileSize + tileSize * .8); - context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .7, c * tileSize + tileSize / 3, r * tileSize + tileSize * .7, c * tileSize + tileSize / 2, r * tileSize + tileSize * .8); - context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .9, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .9, c * tileSize + tileSize, r * tileSize + tileSize * .8); - context.stroke(); - - context.fillStyle = tubColor; - if (!isOccupied(-1, 0)) { - if (isOccupied(-1, -1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize - tileSize * .2, tileSize * .2, tileSize * 1.2, 0, true, false); - else roundRect(context, c * tileSize - tileSize * .1, r * tileSize, tileSize * .2, tileSize, 0, true, false); - } - if (!isOccupied(1, 0)) roundRect(context, c * tileSize + tileSize * .9, r * tileSize, tileSize * .2, tileSize, 0, true, false); - if (!isOccupied(0, 1)) { - if (isOccupied(-1, 1) && !isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize + tileSize * .8, tileSize * 1.1, tileSize * .2, 0, true, false); - else if (!isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize, r * tileSize + tileSize * .8, tileSize * 1.3, tileSize * .2, 0, true, false); - else if (isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize + tileSize * .8, tileSize * 1.1, tileSize * .2, 0, true, false); - else roundRect(context, c * tileSize, r * tileSize + tileSize * .8, tileSize, tileSize * .2, 0, true, false); - } - context.restore(); + roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); + + context.lineWidth = 3; + context.beginPath(); + context.moveTo(c*tileSize, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.1, c*tileSize+tileSize/3, r*tileSize+tileSize*.1, c*tileSize+tileSize/2, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.3, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.3, c*tileSize+tileSize, r*tileSize+tileSize*.2); + context.moveTo(c*tileSize, r*tileSize+tileSize*.4); + context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.3, c*tileSize+tileSize/3, r*tileSize+tileSize*.3, c*tileSize+tileSize/2, r*tileSize+tileSize*.4); + context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.5, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.5, c*tileSize+tileSize, r*tileSize+tileSize*.4); + context.moveTo(c*tileSize, r*tileSize+tileSize*.6); + context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.5, c*tileSize+tileSize/3, r*tileSize+tileSize*.5, c*tileSize+tileSize/2, r*tileSize+tileSize*.6); + context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.7, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.7, c*tileSize+tileSize, r*tileSize+tileSize*.6); + context.moveTo(c*tileSize, r*tileSize+tileSize*.8); + context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.7, c*tileSize+tileSize/3, r*tileSize+tileSize*.7, c*tileSize+tileSize/2, r*tileSize+tileSize*.8); + context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.9, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.9, c*tileSize+tileSize, r*tileSize+tileSize*.8); + context.stroke(); + + context.fillStyle = tubColor; + if(!isOccupied(-1,0)) { + if(isOccupied(-1,-1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize-tileSize*.2, tileSize*.2, tileSize*1.2, 0, true, false); + else roundRect(context, c*tileSize-tileSize*.1, r*tileSize, tileSize*.2, tileSize, 0, true, false); + } + if(!isOccupied(1,0)) roundRect(context, c*tileSize+tileSize*.9, r*tileSize, tileSize*.2, tileSize, 0, true, false); + if(!isOccupied(0,1)) { + if(isOccupied(-1,1) && !isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); + else if(!isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize*1.3, tileSize*.2, 0, true, false); + else if(isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); + else roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize, tileSize*.2, 0, true, false); } + context.restore(); +} - function drawLift(r, c, isFixed) { + function drawLift(r, c, isFixed) { context.lineWidth = .5; context.strokeStyle = "#777"; var strokeBool = false; - if (!isFixed) { + if(!isFixed) { context.fillStyle = "#e68a00"; - roundRect(context, c * tileSize + tileSize * .05, r * tileSize + tileSize, tileSize * .9, tileSize * .2, 2, true, strokeBool); + roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); context.fillStyle = "#cc0000"; - roundRect(context, c * tileSize + tileSize * .3, r * tileSize + tileSize * .8, tileSize * .4, tileSize * .2, { tl: 2, tr: 2 }, true, strokeBool); + roundRect(context, c*tileSize+tileSize*.3, r*tileSize+tileSize*.8, tileSize*.4, tileSize*.2, {tl:2, tr:2}, true, strokeBool); } - else if (isFixed) { + else if(isFixed) { context.fillStyle = "#e68a00"; - roundRect(context, c * tileSize + tileSize * .05, r * tileSize + tileSize * .8, tileSize * .9, tileSize * .2, 2, true, strokeBool); - roundRect(context, c * tileSize + tileSize * .05, r * tileSize, tileSize * .9, tileSize * .2, 2, true, strokeBool); - + roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize*.8, tileSize*.9, tileSize*.2, 2, true, strokeBool); + roundRect(context, c*tileSize+tileSize*.05, r*tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); + context.fillStyle = "#333"; - + context.beginPath(); - context.moveTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .8); - context.lineTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .5); - context.lineTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .2); - context.lineTo(c * tileSize + tileSize * .7, r * tileSize + tileSize * .2); - context.lineTo(c * tileSize + tileSize * .2, r * tileSize + tileSize * .45); - context.bezierCurveTo(c * tileSize + tileSize * .16, r * tileSize + tileSize * .45, c * tileSize + tileSize * .16, r * tileSize + tileSize * .55, c * tileSize + tileSize * .2, r * tileSize + tileSize * .55); - context.lineTo(c * tileSize + tileSize * .7, r * tileSize + tileSize * .8); - context.lineTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .8); + context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.45); + context.bezierCurveTo(c*tileSize+tileSize*.16,r*tileSize+tileSize*.45,c*tileSize+tileSize*.16,r*tileSize+tileSize*.55,c*tileSize+tileSize*.2,r*tileSize+tileSize*.55); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); context.closePath(); context.fill(); - + context.beginPath(); - context.moveTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .8); - context.lineTo(c * tileSize + tileSize * .7, r * tileSize + tileSize * .5); - context.lineTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .2); - context.lineTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .2); - context.lineTo(c * tileSize + tileSize * .8, r * tileSize + tileSize * .45); - context.bezierCurveTo(c * tileSize + tileSize * .84, r * tileSize + tileSize * .45, c * tileSize + tileSize * .84, r * tileSize + tileSize * .55, c * tileSize + tileSize * .8, r * tileSize + tileSize * .55); - context.lineTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .8); - context.lineTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .8); + context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.5); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.45); + context.bezierCurveTo(c*tileSize+tileSize*.84,r*tileSize+tileSize*.45,c*tileSize+tileSize*.84,r*tileSize+tileSize*.55,c*tileSize+tileSize*.8,r*tileSize+tileSize*.55); + context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); + context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.8); context.closePath(); context.fill(); - + /*context.beginPath(); context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.9); context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); @@ -3213,7 +3198,7 @@ function render() { context.closePath(); context.fill();*/ } - + /*var grd = context.createLinearGradient(c*tileSize, r*tileSize, (c+1)*tileSize, (r+1)*tileSize); grd.addColorStop(0, "rgba(255,255,255,.6)"); grd.addColorStop(.1, "rgba(255,255,255,.7)"); @@ -3319,37 +3304,37 @@ function render() { context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.2); context.stroke(); }*/ + } + + function drawWall(r, c, adjacentTiles) { //GOOBY + //drawRect(r, c, "#976537"); + drawTileNew(r, c, isWall, 0.2, material); + drawTileOutlines(r, c, isWall, 0.2, curlyOutline); + context.save(); + if(curlyOutline) drawBushes(r, c, isWall); + context.restore(); + context.fillStyle = "#895C33"; // dirt edge + //drawTileOutlines(r, c, isWall, 0.2, false); + + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; } - - function drawWall(r, c, adjacentTiles) { //GOOBY - //drawRect(r, c, "#976537"); - drawTileNew(r, c, isWall, 0.2, material); - drawTileOutlines(r, c, isWall, 0.2, curlyOutline); - context.save(); - if (curlyOutline) drawBushes(r, c, isWall); - context.restore(); - context.fillStyle = "#895C33"; // dirt edge - //drawTileOutlines(r, c, isWall, 0.2, false); - - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; - } - } - - function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle) { + } + + function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle){ context.fillStyle = fillStyle; - if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { bl: 10, br: 10 }, true, false); - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tr: 10, br: 10 }, true, false); - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { bl: 10 }, true, false); - else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { br: 10 }, true, false); - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tl: 10 }, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tr: 10 }, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 10, true, false); - else roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 0, true, false); - + if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10,br:10}, true, false); + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10}, true, false); + else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {br:10}, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); + else roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); + /*var randomSpot = Math.floor(Math.random() * 5); //random spots on dirt var randomColor = Math.floor(Math.random() * 5); context.beginPath(); @@ -3367,1063 +3352,1062 @@ function render() { } context.stroke();*/ } - - function drawCurves(r, c, adjacentTiles) { + + function drawCurves(r, c, adjacentTiles){ drawCurves2(r, c, isWall, material); - + function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; } } - - function drawCurves2(r, c, isOccupied, material) { + + function drawCurves2(r, c, isOccupied, material){ context.fillStyle = material; - if (isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { - context.fillRect((c + 1) * tileSize, (r + 1) * tileSize, tileSize / 6, tileSize / 6); + if(isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { + context.fillRect((c+1)*tileSize, (r+1)*tileSize, tileSize/6, tileSize/6); //context.globalCompositeOperation = "destination-out"; context.beginPath(); - context.arc((c + 1) * tileSize + tileSize / 6, (r + 1) * tileSize + tileSize / 6, tileSize / 6, 0, 2 * Math.PI); + context.arc((c+1)*tileSize+tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); context.closePath(); - + var bgColor; - if ((c + r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*') + 2, background.length); + if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*')+2, background.length); var r1, r2, b1, b2, g1, g2; - r1 = bgColor.substr(5, bgColor.indexOf(",") - 5); - g1 = bgColor.substr(bgColor.indexOf(",") + 1, bgColor.indexOf(",") - 4); - b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",") + 1) + 1, bgColor.indexOf(",") - 4); - var shade = (r + 1) * .03 + .5; - if (shade > 1) + r1 = bgColor.substr(5, bgColor.indexOf(",")-5); + g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); + var shade = (r+1)*.03+.5; + if(shade>1) shade = 1; - r2 = 255 + (r1 - 255) * shade; - g2 = 255 + (g1 - 255) * shade; - b2 = 255 + (b1 - 255) * shade; + r2 = 255 + (r1-255) * shade; + g2 = 255 + (g1-255) * shade; + b2 = 255 + (b1-255) * shade; context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; context.fill(); - context.globalCompositeOperation = "source-over"; + context.globalCompositeOperation = "source-over"; } - if (isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1) && curlyOutline) { - context.fillRect(c * tileSize - tileSize / 6, (r + 1) * tileSize, tileSize / 6, tileSize / 6); + if(isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1) && curlyOutline) { + context.fillRect(c*tileSize-tileSize/6, (r+1)*tileSize, tileSize/6, tileSize/6); //context.globalCompositeOperation = "destination-out"; context.beginPath(); - context.arc(c * tileSize - tileSize / 6, (r + 1) * tileSize + tileSize / 6, tileSize / 6, 0, 2 * Math.PI); + context.arc(c*tileSize-tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); context.closePath(); - + var bgColor; - if ((c + r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*') + 2, background.length); + if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*')+2, background.length); var r1, r2, b1, b2, g1, g2; - r1 = bgColor.substr(5, bgColor.indexOf(",") - 5); - g1 = bgColor.substr(bgColor.indexOf(",") + 1, bgColor.indexOf(",") - 4); - b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",") + 1) + 1, bgColor.indexOf(",") - 4); - var shade = (r + 1) * .03 + .5; - if (shade > 1) + r1 = bgColor.substr(5, bgColor.indexOf(",")-5); + g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); + var shade = (r+1)*.03+.5; + if(shade>1) shade = 1; - r2 = 255 + (r1 - 255) * shade; - g2 = 255 + (g1 - 255) * shade; - b2 = 255 + (b1 - 255) * shade; + r2 = 255 + (r1-255) * shade; + g2 = 255 + (g1-255) * shade; + b2 = 255 + (b1-255) * shade; context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; context.fill(); context.globalCompositeOperation = "source-over"; } } - - function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { //Gooby - if (surface != "rainbow") { - context.fillStyle = surface; + + function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { //Gooby + if(surface != "rainbow") { + context.fillStyle = surface; + } + else{ + context.fillStyle = "white"; + var mod = (r+c) % 17; + switch(mod){ + case 0: context.fillStyle = "#ff004c"; break; + case 1: context.fillStyle = "#e30000"; break; + case 2: context.fillStyle = "#ff4c00"; break; + case 3: context.fillStyle = "#ff9900"; break; + case 4: context.fillStyle = "#ffe500"; break; + case 5: context.fillStyle = "#cbff00"; break; + case 6: context.fillStyle = "#7fff00"; break; + case 7: context.fillStyle = "#00ff19"; break; + case 8: context.fillStyle = "#00ff66"; break; + case 9: context.fillStyle = "#00ffb2"; break; + case 10: context.fillStyle = "#00ffff"; break; + case 11: context.fillStyle = "#00b2ff"; break; + case 12: context.fillStyle = "#3200ff"; break; + case 13: context.fillStyle = "#5702c6"; break; + case 14: context.fillStyle = "#cc00ff"; break; + case 15: context.fillStyle = "#ff00e5"; break; + case 16: context.fillStyle = "#ff0098"; break; } - else { - context.fillStyle = "white"; - var mod = (r + c) % 17; - switch (mod) { - case 0: context.fillStyle = "#ff004c"; break; - case 1: context.fillStyle = "#e30000"; break; - case 2: context.fillStyle = "#ff4c00"; break; - case 3: context.fillStyle = "#ff9900"; break; - case 4: context.fillStyle = "#ffe500"; break; - case 5: context.fillStyle = "#cbff00"; break; - case 6: context.fillStyle = "#7fff00"; break; - case 7: context.fillStyle = "#00ff19"; break; - case 8: context.fillStyle = "#00ff66"; break; - case 9: context.fillStyle = "#00ffb2"; break; - case 10: context.fillStyle = "#00ffff"; break; - case 11: context.fillStyle = "#00b2ff"; break; - case 12: context.fillStyle = "#3200ff"; break; - case 13: context.fillStyle = "#5702c6"; break; - case 14: context.fillStyle = "#cc00ff"; break; - case 15: context.fillStyle = "#ff00e5"; break; - case 16: context.fillStyle = "#ff0098"; break; - } + } + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + var complementPixels = (1 - 2 * outlineThickness) * tileSize; + + if (curlyOutline && !isOccupied(0, -1)){ + if(!isOccupied(-1, 0) && isOccupied(1, 0)){ + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.4, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize, r*tileSize); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize); + context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); + context.closePath(); } - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - var complementPixels = (1 - 2 * outlineThickness) * tileSize; - - if (curlyOutline && !isOccupied(0, -1)) { - if (!isOccupied(-1, 0) && isOccupied(1, 0)) { - context.beginPath(); - context.moveTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * .05, r * tileSize + tileSize * .3, c * tileSize + tileSize * .3, r * tileSize + tileSize * .4, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * .35, r * tileSize + tileSize * .4, c * tileSize + tileSize * .6, r * tileSize + tileSize * .4, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * .75, r * tileSize + tileSize * .3, c * tileSize + tileSize * .9, r * tileSize + tileSize * .4, c * tileSize + tileSize * 1, r * tileSize + tileSize * .2); - context.lineTo(c * tileSize + tileSize, r * tileSize); - context.lineTo(c * tileSize + tileSize * .2, r * tileSize); - context.bezierCurveTo(c * tileSize - tileSize * .2, r * tileSize - tileSize * .05, c * tileSize - tileSize * .15, r * tileSize + tileSize * .5, c * tileSize + tileSize * .1, r * tileSize + tileSize * .25); - context.closePath(); - } - else if (isOccupied(-1, 0) && !isOccupied(1, 0)) { - context.beginPath(); - context.moveTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * .95, r * tileSize + tileSize * .3, c * tileSize + tileSize * .7, r * tileSize + tileSize * .4, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * .65, r * tileSize + tileSize * .4, c * tileSize + tileSize * .4, r * tileSize + tileSize * .4, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .3, c * tileSize + tileSize * .1, r * tileSize + tileSize * .4, c * tileSize, r * tileSize + tileSize * .2); - context.lineTo(c * tileSize, r * tileSize); - context.lineTo(c * tileSize + tileSize * .8, r * tileSize); - context.bezierCurveTo((c + 1) * tileSize + tileSize * .2, r * tileSize - tileSize * .05, (c + 1) * tileSize + tileSize * .15, r * tileSize + tileSize * .5, (c + 1) * tileSize - tileSize * .1, r * tileSize + tileSize * .25); - context.closePath(); - } - else if (!isOccupied(-1, 0) && !isOccupied(1, 0)) { - context.beginPath(); - context.moveTo(c * tileSize + tileSize * .9, r * tileSize - tileSize * 0); - context.lineTo(c * tileSize + tileSize * .2, r * tileSize); - context.bezierCurveTo(c * tileSize - tileSize * .2, r * tileSize - tileSize * .05, c * tileSize - tileSize * .15, r * tileSize + tileSize * .5, c * tileSize + tileSize * .1, r * tileSize + tileSize * .25); - context.bezierCurveTo(c * tileSize + tileSize * .05, r * tileSize + tileSize * .3, c * tileSize + tileSize * .3, r * tileSize + tileSize * .4, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * .35, r * tileSize + tileSize * .4, c * tileSize + tileSize * .6, r * tileSize + tileSize * .4, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * .75, r * tileSize + tileSize * .3, c * tileSize + tileSize * .8, r * tileSize + tileSize * .4, c * tileSize + tileSize * .9, r * tileSize + tileSize * .2); - context.bezierCurveTo((c + 1) * tileSize - tileSize * .1, r * tileSize + tileSize * .4, (c + 1) * tileSize + tileSize * .3, r * tileSize + tileSize * .3, (c + 1) * tileSize, r * tileSize + tileSize * .02); - context.closePath(); - } - else { - context.beginPath(); - context.moveTo(c * tileSize, r * tileSize); - context.lineTo(c * tileSize, r * tileSize + tileSize * .15); - context.bezierCurveTo(c * tileSize + tileSize * 0, r * tileSize + tileSize * .4, c * tileSize + tileSize * .3, r * tileSize + tileSize * .3, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * .35, r * tileSize + tileSize * .3, c * tileSize + tileSize * .6, r * tileSize + tileSize * .3, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * .75, r * tileSize + tileSize * .4, c * tileSize + tileSize * .9, r * tileSize + tileSize * .3, c * tileSize + tileSize * 1, r * tileSize + tileSize * .2); - context.lineTo(c * tileSize + tileSize, r * tileSize); - context.closePath(); - } - context.fill(); + else if(isOccupied(-1, 0) && !isOccupied(1, 0)){ + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.95, r*tileSize+tileSize*.3, c*tileSize+tileSize*.7, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.65, r*tileSize+tileSize*.4, c*tileSize+tileSize*.4, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.1, r*tileSize+tileSize*.4, c*tileSize, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize+tileSize*.8, r*tileSize); + context.bezierCurveTo((c+1)*tileSize+tileSize*.2, r*tileSize-tileSize*.05, (c+1)*tileSize+tileSize*.15, r*tileSize+tileSize*.5, (c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.25); + context.closePath(); } - else if (!curlyOutline && !isOccupied(0, -1)) { - context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - + else if(!isOccupied(-1, 0) && !isOccupied(1, 0)){ + context.beginPath(); + context.moveTo(c*tileSize+tileSize*.9, r*tileSize-tileSize*0); + context.lineTo(c*tileSize+tileSize*.2, r*tileSize); + context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); + context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.8, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); + context.bezierCurveTo((c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.4, (c+1)*tileSize+tileSize*.3, r*tileSize+tileSize*.3, (c+1)*tileSize, r*tileSize+tileSize*.02); + context.closePath(); + } + else{ + context.beginPath(); + context.moveTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize, r*tileSize+tileSize*.15); + context.bezierCurveTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.4, c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.3, c*tileSize+tileSize*.6, r*tileSize+tileSize*.3, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.lineTo(c*tileSize+tileSize, r*tileSize); + context.closePath(); } - if (!curlyOutline && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied(1, -1)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied(1, 1)) context.fillRect((c + complement) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied(0, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, tileSize, outlinePixels); - if (!curlyOutline && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!curlyOutline && !isOccupied(1, 0)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); + context.fill(); } - - function drawBushes(r, c, isOccupied) { - if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)) { + else if(!curlyOutline && !isOccupied(0, -1)){ context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + + } + if (!curlyOutline && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); + if (!curlyOutline && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!curlyOutline && !isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); + } + + function drawBushes(r, c, isOccupied){ + if(!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)){ /*context.shadowColor = "#666"; context.shadowOffsetX = -.5; context.shadowOffsetY = -.5; context.shadowBlur = 1;*/ - + context.beginPath(); - context.moveTo((c + 1) * tileSize, r * tileSize); - context.lineTo((c + 1) * tileSize, r * tileSize - tileSize * .4); - context.bezierCurveTo((c + 1) * tileSize - tileSize * .1, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .2); - context.bezierCurveTo((c + 1) * tileSize - tileSize * .3, r * tileSize - tileSize * .2, (c + 1) * tileSize - tileSize * .4, r * tileSize - tileSize * .1, (c + 1) * tileSize - tileSize * .3, r * tileSize); - context.lineTo((c + 1) * tileSize, r * tileSize); + context.moveTo((c+1)*tileSize, r*tileSize); + context.lineTo((c+1)*tileSize, r*tileSize-tileSize*.4); + context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); + context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); + context.lineTo((c+1)*tileSize, r*tileSize); context.closePath(); context.fill(); - + context.beginPath(); - context.moveTo((c + 1) * tileSize, r * tileSize - tileSize * .4); - context.bezierCurveTo((c + 1) * tileSize - tileSize * .1, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .2); - context.bezierCurveTo((c + 1) * tileSize - tileSize * .3, r * tileSize - tileSize * .2, (c + 1) * tileSize - tileSize * .4, r * tileSize - tileSize * .1, (c + 1) * tileSize - tileSize * .3, r * tileSize); + context.moveTo((c+1)*tileSize, r*tileSize-tileSize*.4); + context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); + context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); } - - if (!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)) { + + if(!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)){ /*context.shadowColor = "#666"; context.shadowOffsetX = .5; context.shadowOffsetY = -.5; context.shadowBlur = 1;*/ - + context.beginPath(); - context.moveTo(c * tileSize, r * tileSize); - context.lineTo(c * tileSize, r * tileSize - tileSize * .4); - context.bezierCurveTo(c * tileSize + tileSize * .1, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * .3, r * tileSize - tileSize * .2, c * tileSize + tileSize * .4, r * tileSize - tileSize * .1, c * tileSize + tileSize * .3, r * tileSize); - context.lineTo(c * tileSize, r * tileSize); + context.moveTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize, r*tileSize-tileSize*.4); + context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); + context.lineTo(c*tileSize, r*tileSize); context.closePath(); context.fill(); - + context.restore(); - + context.beginPath(); - context.moveTo(c * tileSize, r * tileSize - tileSize * .4); - context.bezierCurveTo(c * tileSize + tileSize * .1, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * .3, r * tileSize - tileSize * .2, c * tileSize + tileSize * .4, r * tileSize - tileSize * .1, c * tileSize + tileSize * .3, r * tileSize); + context.moveTo(c*tileSize, r*tileSize-tileSize*.4); + context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); /*context.strokeStyle = "#7dff1a"; - context.stroke();*/ + context.stroke();*/ } } - - function drawSpikes(r, c, adjacentTiles) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = spikeColors[0]; - - context.beginPath(); - context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes - context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.45, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.55, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.75, y + tileSize * 0.3); - - context.moveTo(x + tileSize * 0.7, y + tileSize * 0.25); //right spikes - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.45); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.55); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.75); - - context.moveTo(x + tileSize * 0.75, y + tileSize * 0.7); //bottom spikes - context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.55, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.45, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.25, y + tileSize * 0.7); - - context.moveTo(x + tileSize * 0.3, y + tileSize * 0.75); //left spikes - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.55); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.45); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); - context.closePath(); - - /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ - context.fill(); - drawSpikeSupports(r, c, isSpike, isWall); - - function isSpike(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === SPIKE; - } - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; - } + + function drawSpikes(r, c, adjacentTiles) { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = spikeColors[0]; + + context.beginPath(); + context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes + context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.45, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.55, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.75, y + tileSize * 0.3); + + context.moveTo(x + tileSize * 0.7, y + tileSize * 0.25); //right spikes + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.45); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.55); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.75); + + context.moveTo(x + tileSize * 0.75, y + tileSize * 0.7); //bottom spikes + context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.55, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.45, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.25, y + tileSize * 0.7); + + context.moveTo(x + tileSize * 0.3, y + tileSize * 0.75); //left spikes + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.55); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.45); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); + context.closePath(); + + /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ + context.fill(); + drawSpikeSupports(r, c, isSpike, isWall); + + function isSpike(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === SPIKE; } - - function drawSpikeSupports(r, c, isOccupied, canConnect) { + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } + } + + function drawSpikeSupports(r, c, isOccupied, canConnect){ var boltBool = false; var occupiedCount = 0; - if (canConnect(0, 1)) { + if(canConnect(0, 1)){ context.fillStyle = spikeColors[1]; - context.fillRect(c * tileSize + (tileSize * .3), r * tileSize + (tileSize * .8), tileSize * .4, tileSize * .4); + context.fillRect(c*tileSize+(tileSize*.3), r*tileSize+(tileSize*.8), tileSize*.4, tileSize*.4); boltBool = true; } - if (canConnect(0, -1) && !canConnect(0, 1)) { - if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(1, -1)) { } - else { + if(canConnect(0, -1) && !canConnect(0, 1)){ + if(!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(1, -1)){} + else{ context.fillStyle = spikeColors[1]; - context.fillRect(c * tileSize + (tileSize * .3), r * tileSize, tileSize * .4, tileSize * .4); + context.fillRect(c*tileSize+(tileSize*.3), r*tileSize, tileSize*.4, tileSize*.4); boltBool = true; } } - if (canConnect(-1, 0) && !canConnect(0, 1)) { - if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(-1, 1)) { } - else { + if(canConnect(-1, 0) && !canConnect(0, 1)){ + if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(-1, 1)){} + else{ context.fillStyle = spikeColors[1]; - context.fillRect(c * tileSize, r * tileSize + (tileSize * .3), tileSize * .4, tileSize * .4); + context.fillRect(c*tileSize, r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); boltBool = true; } } - if (canConnect(1, 0) && !canConnect(0, 1)) { - if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(1, -1) && canConnect(1, 1)) { } - else { + if(canConnect(1, 0) && !canConnect(0, 1)){ + if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(1, -1) && canConnect(1, 1)){} + else{ context.fillStyle = spikeColors[1]; - context.fillRect(c * tileSize + (tileSize * .8), r * tileSize + (tileSize * .3), tileSize * .4, tileSize * .4); + context.fillRect(c*tileSize+(tileSize*.8), r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); boltBool = true; } } - + context.fillStyle = spikeColors[2]; - if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING ONE - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, { bl: 4, br: 4 }, true, false); + if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING ONE + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4,br:4}, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) { - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize, tileSize * .6, { tl: 4, bl: 4 }, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize, tileSize*.6, {tl:4,bl:4}, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, { tl: 4, tr: 4 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4,tr:4}, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { - roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { tr: 4, br: 4 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4,br:4}, true, false); boltBool = true; } - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING TWO (CORNERS) - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, { bl: 4 }, true, false); - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { bl: 4 }, true, false); - if (!canConnect(1, -1)) boltBool = true; - } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { - roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { br: 4 }, true, false); - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, { br: 4 }, true, false); - if (!canConnect(-1, -1)) boltBool = true; - } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { tl: 4 }, true, false); - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, { tl: 4 }, true, false); - if (!canConnect(1, 1)) boltBool = true; - } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { - roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { tr: 4 }, true, false); - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, { tr: 4 }, true, false); - if (!canConnect(-1, 1)) boltBool = true; + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (CORNERS) + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4}, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {bl:4}, true, false); + if(!canConnect(1, -1)) boltBool = true; } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING TWO (OPPOSITES) - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); + else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {br:4}, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {br:4}, true, false); + if(!canConnect(-1, -1)) boltBool = true; } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { - roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tl:4}, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4}, true, false); + if(!canConnect(1, 1)) boltBool = true; + } + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4}, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tr:4}, true, false); + if(!canConnect(-1, 1)) boltBool = true; + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (OPPOSITES) + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); } - else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING THREE - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { - roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); - roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, 0, true, false); - boltBool = true; + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { - roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, 0, true, false); + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING THREE + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, 0, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); boltBool = true; } - else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { //TOUCHING FOUR - roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, 0, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ //TOUCHING FOUR + roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); //boltBool = true; } - else { - roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .6, 0, true, false); + else{ + roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.6, 0, true, false); boltBool = true; } - + if (boltBool) drawBolt(r, c); } - - function drawBolt(r, c) { + + function drawBolt(r, c){ context.strokeStyle = spikeColors[3]; context.beginPath(); - context.arc(c * tileSize + (tileSize * .55), r * tileSize + (tileSize * .45), 4, -.7 * Math.PI, .2 * Math.PI); - context.lineTo(c * tileSize + (tileSize * .45), r * tileSize + (tileSize * .35)); + context.arc(c*tileSize+(tileSize*.55), r*tileSize+(tileSize*.45), 4, -.7*Math.PI, .2*Math.PI); + context.lineTo(c*tileSize+(tileSize*.45),r*tileSize+(tileSize*.35)); context.closePath(); context.fillStyle = spikeColors[3]; context.fill(); context.stroke(); - + context.beginPath(); - context.moveTo(c * tileSize + (tileSize * .43), r * tileSize + (tileSize * .47)); - context.arc(c * tileSize + (tileSize * .48), r * tileSize + (tileSize * .52), 4, .2 * Math.PI, -.75 * Math.PI); + context.moveTo(c*tileSize+(tileSize*.43),r*tileSize+(tileSize*.47)); + context.arc(c*tileSize+(tileSize*.48), r*tileSize+(tileSize*.52), 4, .2*Math.PI, -.75*Math.PI); //context.lineTo(c*tileSize+(tileSize*.4),r*tileSize+(tileSize*.6)); context.closePath(); context.fillStyle = spikeColors[3]; context.fill(); context.stroke(); } - - function drawConnector(context, r1, c1, r2, c2, color) { - // either r1 and r2 or c1 and c2 must be equal - if (r1 > r2 || c1 > c2) { - var rTmp = r1; - var cTmp = c1; - r1 = r2; - c1 = c2; - r2 = rTmp; - c2 = cTmp; - } - var xLo = (c1 + 0.3) * tileSize; - var yLo = (r1 + 0.3) * tileSize; - var xHi = (c2 + 0.45) * tileSize; - var yHi = (r2 + 0.45) * tileSize; - context.fillStyle = color; - context.fillRect(xLo + .15 * tileSize, yLo + .15 * tileSize, xHi - xLo, yHi - yLo); - } - function drawBlock(block) { - var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); - var rowcols = block.locations.map(function (location) { - return getRowcol(level, location); - }); - rowcols.forEach(function (rowcol) { - var r = rowcol.r + animationDisplacementRowcol.r; - var c = rowcol.c + animationDisplacementRowcol.c; - context.fillStyle = blockColors[0][block.id % blockColors[0].length]; - var outlineThickness = .2; - - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - if (!isAlsoThisBlock(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock(1, -1)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock(-1, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock(1, 1)) context.fillRect((c + complement) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock(0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - if (!isAlsoThisBlock(0, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, tileSize, outlinePixels); - if (!isAlsoThisBlock(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!isAlsoThisBlock(1, 0)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); - - function isAlsoThisBlock(dc, dr) { - for (var i = 0; i < rowcols.length; i++) { - var otherRowcol = rowcols[i]; - if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; - } - return false; - } - }); - } - function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { - var cx = (c + 0.5) * tileSize; - var cy = (r + 0.5) * tileSize; - context.fillStyle = fillStyle; - context.beginPath(); - context.moveTo(cx, cy); - context.arc(cx, cy, radiusFactor * tileSize / 2, quadrant * Math.PI / 2, (quadrant + 1) * Math.PI / 2); - context.fill(); - } - function drawDiamond(r, c, fillStyle) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = fillStyle; - roundRect(context, x, y, tileSize, tileSize, 10, true, false); - } - function drawCircle(r, c, radiusFactor, fillStyle) { - context.fillStyle = fillStyle; - context.beginPath(); - context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize / 2 * radiusFactor, 0, 2 * Math.PI); - context.fill(); - } - function drawRect(r, c, fillStyle) { - context.fillStyle = fillStyle; - context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); + + function drawConnector(context, r1, c1, r2, c2, color) { + // either r1 and r2 or c1 and c2 must be equal + if (r1 > r2 || c1 > c2) { + var rTmp = r1; + var cTmp = c1; + r1 = r2; + c1 = c2; + r2 = rTmp; + c2 = cTmp; } - - function drawCloud(c, x, y) { + var xLo = (c1 + 0.3) * tileSize; + var yLo = (r1 + 0.3) * tileSize; + var xHi = (c2 + 0.45) * tileSize; + var yHi = (r2 + 0.45) * tileSize; + context.fillStyle = color; + context.fillRect(xLo+.15*tileSize, yLo+.15*tileSize, xHi - xLo, yHi - yLo); + } + function drawBlock(block) { + var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); + var rowcols = block.locations.map(function(location) { + return getRowcol(level, location); + }); + rowcols.forEach(function(rowcol) { + var r = rowcol.r + animationDisplacementRowcol.r; + var c = rowcol.c + animationDisplacementRowcol.c; + context.fillStyle = blockColors[0][block.id % blockColors[0].length]; + var outlineThickness = .2; + + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + if (!isAlsoThisBlock(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + if (!isAlsoThisBlock( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); + if (!isAlsoThisBlock(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!isAlsoThisBlock( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); + + function isAlsoThisBlock(dc, dr) { + for (var i = 0; i < rowcols.length; i++) { + var otherRowcol = rowcols[i]; + if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; + } + return false; + } + }); + } + function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { + var cx = (c + 0.5) * tileSize; + var cy = (r + 0.5) * tileSize; + context.fillStyle = fillStyle; + context.beginPath(); + context.moveTo(cx, cy); + context.arc(cx, cy, radiusFactor * tileSize/2, quadrant * Math.PI/2, (quadrant + 1) * Math.PI/2); + context.fill(); + } + function drawDiamond(r, c, fillStyle) { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = fillStyle; + roundRect(context, x, y, tileSize, tileSize, 10, true, false); + } + function drawCircle(r, c, radiusFactor, fillStyle) { + context.fillStyle = fillStyle; + context.beginPath(); + context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize/2 * radiusFactor, 0, 2*Math.PI); + context.fill(); + } + function drawRect(r, c, fillStyle) { + context.fillStyle = fillStyle; + context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); + } + + function drawCloud(c, x, y){ c.fillStyle = experimentalColors[0]; /*c.beginPath(); c.rect(x, y, tileSize, tileSize); c.fill(); c.closePath();*/ - + c.beginPath(); - c.moveTo(x + tileSize * 0, y + tileSize * 0); - - c.bezierCurveTo(x + tileSize * 0, y - tileSize * .15, x + tileSize * .33, y - tileSize * .15, x + tileSize * .33, y + tileSize * 0); - c.bezierCurveTo(x + tileSize * .33, y - tileSize * .15, x + tileSize * .67, y - tileSize * .15, x + tileSize * .67, y + tileSize * 0); - c.bezierCurveTo(x + tileSize * .67, y - tileSize * .15, x + tileSize * 1, y - tileSize * .15, x + tileSize * 1, y + tileSize * 0); - - c.bezierCurveTo(x + tileSize * 1.15, y + tileSize * 0, x + tileSize * 1.15, y + tileSize * .33, x + tileSize * 1, y + tileSize * .33); - c.bezierCurveTo(x + tileSize * 1.15, y + tileSize * .33, x + tileSize * 1.15, y + tileSize * .67, x + tileSize * 1, y + tileSize * .67); - c.bezierCurveTo(x + tileSize * 1.15, y + tileSize * .67, x + tileSize * 1.15, y + tileSize * 1, x + tileSize * 1, y + tileSize * 1); - - c.bezierCurveTo(x + tileSize * 1, y + tileSize * 1.15, x + tileSize * .67, y + tileSize * 1.15, x + tileSize * .67, y + tileSize * 1); - c.bezierCurveTo(x + tileSize * .67, y + tileSize * 1.15, x + tileSize * .33, y + tileSize * 1.15, x + tileSize * .33, y + tileSize * 1); - c.bezierCurveTo(x + tileSize * .33, y + tileSize * 1.15, x + tileSize * 0, y + tileSize * 1.15, x + tileSize * 0, y + tileSize * 1); - - c.bezierCurveTo(x - tileSize * .15, y + tileSize * 1, x - tileSize * .15, y + tileSize * .67, x + tileSize * 0, y + tileSize * .67); - c.bezierCurveTo(x - tileSize * .15, y + tileSize * .67, x - tileSize * .15, y + tileSize * .33, x + tileSize * 0, y + tileSize * .33); - c.bezierCurveTo(x - tileSize * .15, y + tileSize * .33, x - tileSize * .15, y + tileSize * 0, x + tileSize * 0, y + tileSize * 0); - + c.moveTo(x+tileSize*0, y+tileSize*0); + + c.bezierCurveTo(x+tileSize*0, y-tileSize*.15, x+tileSize*.33, y-tileSize*.15, x+tileSize*.33, y+tileSize*0); + c.bezierCurveTo(x+tileSize*.33, y-tileSize*.15, x+tileSize*.67, y-tileSize*.15, x+tileSize*.67, y+tileSize*0); + c.bezierCurveTo(x+tileSize*.67, y-tileSize*.15, x+tileSize*1, y-tileSize*.15, x+tileSize*1, y+tileSize*0); + + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*0, x+tileSize*1.15, y+tileSize*.33, x+tileSize*1, y+tileSize*.33); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.33, x+tileSize*1.15, y+tileSize*.67, x+tileSize*1, y+tileSize*.67); + c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.67, x+tileSize*1.15, y+tileSize*1, x+tileSize*1, y+tileSize*1); + + c.bezierCurveTo(x+tileSize*1, y+tileSize*1.15, x+tileSize*.67, y+tileSize*1.15, x+tileSize*.67, y+tileSize*1); + c.bezierCurveTo(x+tileSize*.67, y+tileSize*1.15, x+tileSize*.33, y+tileSize*1.15, x+tileSize*.33, y+tileSize*1); + c.bezierCurveTo(x+tileSize*.33, y+tileSize*1.15, x+tileSize*0, y+tileSize*1.15, x+tileSize*0, y+tileSize*1); + + c.bezierCurveTo(x-tileSize*.15, y+tileSize*1, x-tileSize*.15, y+tileSize*.67, x+tileSize*0, y+tileSize*.67); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*.67, x-tileSize*.15, y+tileSize*.33, x+tileSize*0, y+tileSize*.33); + c.bezierCurveTo(x-tileSize*.15, y+tileSize*.33, x-tileSize*.15, y+tileSize*0, x+tileSize*0, y+tileSize*0); + c.closePath(); c.fill(); //c.stroke(); } - function drawFace(snake, headCol, headRow, orientation) { - var x = headCol * tileSize; - var y = headRow * tileSize; - - var scaleFactor = 1.5; - var scale1; - var scale2; - var eye1 = tileSize * .8; - var eye2 = tileSize * .4; - - var eyeSize = tileSize / 5; - var eyeRotation = 2; - var z1, z2, z3, z4, z5, z6, z7, z8; - var a1, a2, a3, a4, a5, a6, a7, a8; - var beakRotation = 1.5; - var arcDirection = false; - - switch (orientation) { - case 0: //red up and blue left - z1 = eye2; - z2 = tileSize - eye1; - z3 = eye2; - z4 = tileSize - eye2; - z5 = eye2; - z6 = tileSize - eye1; - z7 = eye2; - z8 = tileSize - eye2 - eyeRotation = 1.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize * .7; - a2 = tileSize - tileSize * .7; - a3 = tileSize * .7; - a4 = -tileSize * .3; - a5 = tileSize * .7; - a6 = tileSize * .3; - a7 = tileSize / 6; - a8 = 0; - beakRotation = 1; - arcDirection = false; - break; - case 1: //red right and blue up - z1 = eye1; - z2 = eye2; - z3 = eye2; - z4 = eye2; - z5 = eye1; - z6 = eye2; - z7 = eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize * .7; - a2 = tileSize * .7; - a3 = tileSize * 1.3; - a4 = tileSize * .7; - a5 = tileSize * .7; - a6 = tileSize * .7; - a7 = 0; - a8 = tileSize / 6; - beakRotation = 1.5; - arcDirection = false; - break; - case 2: //red down and blue right - z1 = tileSize - eye2; - z2 = eye1; - z3 = tileSize - eye2; - z4 = eye2; - z5 = tileSize - eye2; - z6 = eye1; - z7 = tileSize - eye2; - z8 = eye2; - eyeRotation = 2.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize - tileSize * .7; - a2 = tileSize * .7; - a3 = tileSize - tileSize * .7; - a4 = tileSize * 1.3; - a5 = tileSize - tileSize * .7; - a6 = tileSize * .7; - a7 = tileSize / 6; - a8 = 0; - beakRotation = 1; - arcDirection = true; - break; - case 3: //red left and blue down - z1 = tileSize - eye1; - z2 = tileSize - eye2; - z3 = tileSize - eye2; - z4 = tileSize - eye2; - z5 = tileSize - eye1; - z6 = tileSize - eye2; - z7 = tileSize - eye2; - z8 = tileSize - eye2; - eyeRotation = 3; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize - tileSize * .7; - a2 = tileSize - tileSize * .7; - a3 = tileSize - tileSize * 1.3; - a4 = tileSize - tileSize * .7; - a5 = tileSize - tileSize * .7; - a6 = tileSize - tileSize * .7; - a7 = 0; - a8 = tileSize / 6; - beakRotation = 1.5; - arcDirection = true; - break; - case 4: //green up and yellow right - z1 = tileSize - eye2; - z2 = tileSize - eye1; - z3 = tileSize - eye2; - z4 = tileSize - eye2; - z5 = tileSize - eye2; - z6 = tileSize - eye1; - z7 = tileSize - eye2; - z8 = tileSize - eye2 - eyeRotation = 2.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize - tileSize * .7; - a2 = tileSize - tileSize * .7; - a3 = tileSize - tileSize * .7; - a4 = -tileSize * .3; - a5 = tileSize - tileSize * .7; - a6 = tileSize * .3; - a7 = tileSize / 6; - a8 = 0; - beakRotation = 1; - arcDirection = false; - break; - case 5: //green right and yellow down - z1 = eye1; - z2 = tileSize - eye2; - z3 = eye2; - z4 = tileSize - eye2; - z5 = eye1; - z6 = tileSize - eye2; - z7 = eye2; - z8 = tileSize - eye2; - eyeRotation = 3; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize * .7; - a2 = tileSize - tileSize * .7; - a3 = tileSize * 1.3; - a4 = tileSize - tileSize * .7; - a5 = tileSize * .7; - a6 = tileSize - tileSize * .7; - a7 = 0; - a8 = tileSize / 6; - beakRotation = 1.5; - arcDirection = false; - break; - case 6: //green down and yellow left - z1 = eye2; - z2 = eye1; - z3 = eye2; - z4 = eye2; - z5 = eye2; - z6 = eye1; - z7 = eye2; - z8 = eye2; - eyeRotation = 1.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize * .7; - a2 = tileSize * .7; - a3 = tileSize * .7; - a4 = tileSize * 1.3; - a5 = tileSize * .7; - a6 = tileSize * .7; - a7 = tileSize / 6; - a8 = 0; - beakRotation = 1; - arcDirection = true; - break; - case 7: //green left and yellow up - z1 = tileSize - eye1; - z2 = eye2; - z3 = tileSize - eye2; - z4 = eye2; - z5 = tileSize - eye1; - z6 = eye2; - z7 = tileSize - eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize - tileSize * .7; - a2 = tileSize * .7; - a3 = tileSize - tileSize * 1.3; - a4 = tileSize * .7; - a5 = tileSize - tileSize * .7; - a6 = tileSize * .7; - a7 = 0; - a8 = tileSize / 6; - beakRotation = 1.5; - arcDirection = true; - break; - case 10: //single unit snake - z1 = eye1; - z2 = eye2; - z3 = eye2; - z4 = eye2; - z5 = eye1; - z6 = eye2; - z7 = eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize * .7; - a2 = tileSize * .7; - a3 = tileSize * 1.3; - a4 = tileSize * .7; - a5 = tileSize * .7; - a6 = tileSize * .7; - a7 = 0; - a8 = tileSize / 6; - beakRotation = 1.5; - arcDirection = false; - break; - } - - if (snake === activeSnakeId) { //draw eyes for active snake only - context.fillStyle = "white"; - context.save(); - context.scale(scale1, scale2); - context.beginPath(); - context.arc((x + z1) / scale1, (y + z2) / scale2, eyeSize, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); - - context.fillStyle = "white"; - context.save(); - context.scale(scale1, scale2); - context.beginPath(); - context.arc((x + z3) / scale1, (y + z4) / scale2, eyeSize, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); +function drawFace(snake, headCol, headRow, orientation){ + var x = headCol * tileSize; + var y = headRow * tileSize; + + var scaleFactor = 1.5; + var scale1; + var scale2; + var eye1 = tileSize*.8; + var eye2 = tileSize*.4; + + var eyeSize = tileSize/5; + var eyeRotation = 2; + var z1, z2, z3, z4, z5, z6, z7, z8; + var a1, a2, a3, a4, a5, a6, a7, a8; + var beakRotation = 1.5; + var arcDirection = false; + + switch(orientation){ + case 0: //red up and blue left + z1 = eye2; + z2 = tileSize-eye1; + z3 = eye2; + z4 = tileSize-eye2; + z5 = eye2; + z6 = tileSize-eye1; + z7 = eye2; + z8 = tileSize-eye2 + eyeRotation = 1.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize*.7; + a2 = tileSize-tileSize*.7; + a3 = tileSize*.7; + a4 = -tileSize*.3; + a5 = tileSize*.7; + a6 = tileSize*.3; + a7 = tileSize/6; + a8 = 0; + beakRotation = 1; + arcDirection = false; + break; + case 1: //red right and blue up + z1 = eye1; + z2 = eye2; + z3 = eye2; + z4 = eye2; + z5 = eye1; + z6 = eye2; + z7 = eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize*1.3; + a4 = tileSize*.7; + a5 = tileSize*.7; + a6 = tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = false; + break; + case 2: //red down and blue right + z1 = tileSize-eye2; + z2 = eye1; + z3 = tileSize-eye2; + z4 = eye2; + z5 = tileSize-eye2; + z6 = eye1; + z7 = tileSize-eye2; + z8 = eye2; + eyeRotation = 2.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize-tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize-tileSize*.7; + a4 = tileSize*1.3; + a5 = tileSize-tileSize*.7; + a6 = tileSize*.7; + a7 = tileSize/6; + a8 = 0; + beakRotation = 1; + arcDirection = true; + break; + case 3: //red left and blue down + z1 = tileSize-eye1; + z2 = tileSize-eye2; + z3 = tileSize-eye2; + z4 = tileSize-eye2; + z5 = tileSize-eye1; + z6 = tileSize-eye2; + z7 = tileSize-eye2; + z8 = tileSize-eye2; + eyeRotation = 3; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize-tileSize*.7; + a2 = tileSize-tileSize*.7; + a3 = tileSize-tileSize*1.3; + a4 = tileSize-tileSize*.7; + a5 = tileSize-tileSize*.7; + a6 = tileSize-tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = true; + break; + case 4: //green up and yellow right + z1 = tileSize-eye2; + z2 = tileSize-eye1; + z3 = tileSize-eye2; + z4 = tileSize-eye2; + z5 = tileSize-eye2; + z6 = tileSize-eye1; + z7 = tileSize-eye2; + z8 = tileSize-eye2 + eyeRotation = 2.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize-tileSize*.7; + a2 = tileSize-tileSize*.7; + a3 = tileSize-tileSize*.7; + a4 = -tileSize*.3; + a5 = tileSize-tileSize*.7; + a6 = tileSize*.3; + a7 = tileSize/6; + a8 = 0; + beakRotation = 1; + arcDirection = false; + break; + case 5: //green right and yellow down + z1 = eye1; + z2 = tileSize-eye2; + z3 = eye2; + z4 = tileSize-eye2; + z5 = eye1; + z6 = tileSize-eye2; + z7 = eye2; + z8 = tileSize-eye2; + eyeRotation = 3; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize*.7; + a2 = tileSize-tileSize*.7; + a3 = tileSize*1.3; + a4 = tileSize-tileSize*.7; + a5 = tileSize*.7; + a6 = tileSize-tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = false; + break; + case 6: //green down and yellow left + z1 = eye2; + z2 = eye1; + z3 = eye2; + z4 = eye2; + z5 = eye2; + z6 = eye1; + z7 = eye2; + z8 = eye2; + eyeRotation = 1.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize*.7; + a4 = tileSize*1.3; + a5 = tileSize*.7; + a6 = tileSize*.7; + a7 = tileSize/6; + a8 = 0; + beakRotation = 1; + arcDirection = true; + break; + case 7: //green left and yellow up + z1 = tileSize-eye1; + z2 = eye2; + z3 = tileSize-eye2; + z4 = eye2; + z5 = tileSize-eye1; + z6 = eye2; + z7 = tileSize-eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize-tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize-tileSize*1.3; + a4 = tileSize*.7; + a5 = tileSize-tileSize*.7; + a6 = tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = true; + break; + case 10: //single unit snake + z1 = eye1; + z2 = eye2; + z3 = eye2; + z4 = eye2; + z5 = eye1; + z6 = eye2; + z7 = eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize*.7; + a2 = tileSize*.7; + a3 = tileSize*1.3; + a4 = tileSize*.7; + a5 = tileSize*.7; + a6 = tileSize*.7; + a7 = 0; + a8 = tileSize/6; + beakRotation = 1.5; + arcDirection = false; + break; + } + + if (snake === activeSnakeId) { //draw eyes for active snake only + context.fillStyle = "white"; + context.save(); + context.scale(scale1,scale2); + context.beginPath(); + context.arc((x+z1)/scale1, (y+z2)/scale2, eyeSize, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); - context.fillStyle = "black"; - context.save(); - context.scale(scale1, scale2); - context.beginPath(); - context.arc((x + z5) / scale1, (y + z6) / scale2, eyeSize / 2, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); + context.fillStyle = "white"; + context.save(); + context.scale(scale1,scale2); + context.beginPath(); + context.arc((x+z3)/scale1, (y+z4)/scale2, eyeSize, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); - context.fillStyle = "black"; - context.save(); - context.scale(scale1, scale2); - context.beginPath(); - context.arc((x + z7) / scale1, (y + z8) / scale2, eyeSize / 2, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); - } + context.fillStyle = "black"; + context.save(); + context.scale(scale1,scale2); + context.beginPath(); + context.arc((x+z5)/scale1, (y+z6)/scale2, eyeSize/2, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); - //beak - context.fillStyle = "#F9921C"; + context.fillStyle = "black"; + context.save(); + context.scale(scale1,scale2); context.beginPath(); - context.arc(x + a1, y + a2, tileSize / 6, (beakRotation - 1) * Math.PI, beakRotation * Math.PI, arcDirection); - context.lineTo(x + a3, y + a4); - context.lineTo(x + a5 + a7, y + a6 + a8); + context.arc((x+z7)/scale1, (y+z8)/scale2, eyeSize/2, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); context.closePath(); + context.restore(); context.fill(); } - + + //beak + context.fillStyle = "#F9921C"; + context.beginPath(); + context.arc(x+a1, y+a2, tileSize/6, (beakRotation-1)*Math.PI, beakRotation*Math.PI, arcDirection); + context.lineTo(x+a3, y+a4); + context.lineTo(x+a5+a7, y+a6+a8); + context.closePath(); + context.fill(); +} + function roundRect(ctx, x, y, width, height, radius, fill, stroke) { //Gooby - if (typeof stroke === 'undefined') { - stroke = true; - } - if (typeof radius === 'undefined') { - radius = 5; - } - if (typeof radius === 'number') { - radius = { tl: radius, tr: radius, br: radius, bl: radius }; - } else { - var defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 }; - for (var side in defaultRadius) { - radius[side] = radius[side] || defaultRadius[side]; - } - } - ctx.beginPath(); - ctx.moveTo(x + radius.tl, y); - ctx.lineTo(x + width - radius.tr, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); - ctx.lineTo(x + width, y + height - radius.br); - ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); - ctx.lineTo(x + radius.bl, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl); - ctx.lineTo(x, y + radius.tl); - ctx.quadraticCurveTo(x, y, x + radius.tl, y); - ctx.closePath(); - if (fill) { - ctx.fill(); - } - if (stroke) { - ctx.stroke(); + if (typeof stroke === 'undefined') { + stroke = true; + } + if (typeof radius === 'undefined') { + radius = 5; + } + if (typeof radius === 'number') { + radius = {tl: radius, tr: radius, br: radius, bl: radius}; + } else { + var defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0}; + for (var side in defaultRadius) { + radius[side] = radius[side] || defaultRadius[side]; } + } + ctx.beginPath(); + ctx.moveTo(x + radius.tl, y); + ctx.lineTo(x + width - radius.tr, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); + ctx.lineTo(x + width, y + height - radius.br); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); + ctx.lineTo(x + radius.bl, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl); + ctx.lineTo(x, y + radius.tl); + ctx.quadraticCurveTo(x, y, x + radius.tl, y); + ctx.closePath(); + if (fill) { + ctx.fill(); + } + if (stroke) { + ctx.stroke(); + } } + +function shadeColor(color, percent) { - function shadeColor(color, percent) { - - var R = parseInt(color.substring(1, 3), 16); - var G = parseInt(color.substring(3, 5), 16); - var B = parseInt(color.substring(5, 7), 16); + var R = parseInt(color.substring(1,3),16); + var G = parseInt(color.substring(3,5),16); + var B = parseInt(color.substring(5,7),16); - R = parseInt(R * (100 + percent) / 100); - G = parseInt(G * (100 + percent) / 100); - B = parseInt(B * (100 + percent) / 100); + R = parseInt(R * (100 + percent) / 100); + G = parseInt(G * (100 + percent) / 100); + B = parseInt(B * (100 + percent) / 100); - R = (R < 255) ? R : 255; - G = (G < 255) ? G : 255; - B = (B < 255) ? B : 255; + R = (R<255)?R:255; + G = (G<255)?G:255; + B = (B<255)?B:255; - var RR = ((R.toString(16).length == 1) ? "0" + R.toString(16) : R.toString(16)); - var GG = ((G.toString(16).length == 1) ? "0" + G.toString(16) : G.toString(16)); - var BB = ((B.toString(16).length == 1) ? "0" + B.toString(16) : B.toString(16)); - - return "#" + RR + GG + BB; - } + var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16)); + var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16)); + var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16)); + return "#"+RR+GG+BB; +} - function drawR(r, c, fillStyle) { //Gooby + + function drawR(r,c,fillStyle){ //Gooby context.fillStyle = fillStyle; var cornerRadius = 20; context.lineJoin = "round"; context.lineWidth = 1; - context.strokeRect(c * tileSize, r * tileSize, tileSize, tileSize); + context.strokeRect(c*tileSize, r*tileSize, tileSize, tileSize); //context.fillRect(c*tileSize, r*tileSize, tileSize, tileSize); } - function drawGrid() { - var buffer = document.createElement("canvas"); - buffer.width = canvas.width; - buffer.height = canvas.height; - var localContext = buffer.getContext("2d"); - - localContext.strokeStyle = "#fff"; - localContext.beginPath(); - for (var r = 0; r < level.height; r++) { - localContext.moveTo(0, tileSize * r); - localContext.lineTo(tileSize * level.width, tileSize * r); - } - for (var c = 0; c < level.width; c++) { - localContext.moveTo(tileSize * c, 0); - localContext.lineTo(tileSize * c, tileSize * level.height); - } - localContext.stroke(); + function drawGrid() { + var buffer = document.createElement("canvas"); + buffer.width = canvas.width; + buffer.height = canvas.height; + var localContext = buffer.getContext("2d"); - context.save(); - context.globalAlpha = 0.4; - context.drawImage(buffer, 0, 0); - context.restore(); + localContext.strokeStyle = "#fff"; + localContext.beginPath(); + for (var r = 0; r < level.height; r++) { + localContext.moveTo(0, tileSize*r); + localContext.lineTo(tileSize*level.width, tileSize*r); } + for (var c = 0; c < level.width; c++) { + localContext.moveTo(tileSize*c, 0); + localContext.lineTo(tileSize*c, tileSize*level.height); + } + localContext.stroke(); + + context.save(); + context.globalAlpha = 0.4; + context.drawImage(buffer, 0, 0); + context.restore(); + } } function findAnimation(animationTypes, objectId) { - if (animationQueueCursor === animationQueue.length) return null; - var currentAnimation = animationQueue[animationQueueCursor]; - for (var i = 1; i < currentAnimation.length; i++) { - var animation = currentAnimation[i]; - if (animationTypes.indexOf(animation[0]) !== -1 && animation[1] === objectId) return animation; - } + if (animationQueueCursor === animationQueue.length) return null; + var currentAnimation = animationQueue[animationQueueCursor]; + for (var i = 1; i < currentAnimation.length; i++) { + var animation = currentAnimation[i]; + if (animationTypes.indexOf(animation[0]) !== -1 && animation[1] === objectId) return animation; + } } function findAnimationDisplacementRowcol(objectType, objectId) { - var dr = 0; - var dc = 0; - var animationTypes = [ - "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK - "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK - ]; - // skip the current one - for (var i = animationQueueCursor + 1; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === objectId) { - dr += animation[2]; - dc += animation[3]; - } - } + var dr = 0; + var dc = 0; + var animationTypes = [ + "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK + "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK + ]; + // skip the current one + for (var i = animationQueueCursor + 1; i < animationQueue.length; i++) { + var animations = animationQueue[i]; + for (var j = 1; j < animations.length; j++) { + var animation = animations[j]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === objectId) { + dr += animation[2]; + dc += animation[3]; + } } - var movementAnimation = findAnimation(animationTypes, objectId); - if (movementAnimation != null) { - dr += movementAnimation[2] * (1 - animationProgress); - dc += movementAnimation[3] * (1 - animationProgress); - } - return { r: -dr, c: -dc }; + } + var movementAnimation = findAnimation(animationTypes, objectId); + if (movementAnimation != null) { + dr += movementAnimation[2] * (1 - animationProgress); + dc += movementAnimation[3] * (1 - animationProgress); + } + return {r: -dr, c: -dc}; } function hasFutureRemoveAnimation(object) { - var animationTypes = [ - EXIT_SNAKE, - DIE_BLOCK, - ]; - for (var i = animationQueueCursor; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === object.id) { - return true; - } - } + var animationTypes = [ + EXIT_SNAKE, + DIE_BLOCK, + ]; + for (var i = animationQueueCursor; i < animationQueue.length; i++) { + var animations = animationQueue[i]; + for (var j = 1; j < animations.length; j++) { + var animation = animations[j]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === object.id) { + return true; + } } + } } function previewPaste(hoverR, hoverC) { - var offsetR = hoverR - clipboardOffsetRowcol.r; - var offsetC = hoverC - clipboardOffsetRowcol.c; - - var newLevel = JSON.parse(JSON.stringify(level)); - var selectedLocations = []; - var selectedObjects = []; - clipboardData.selectedLocations.forEach(function (location) { - var tileCode = clipboardData.level.map[location]; - var rowcol = getRowcol(clipboardData.level, location); - var r = rowcol.r + offsetR; - var c = rowcol.c + offsetC; - if (!isInBounds(newLevel, r, c)) return; - var newLocation = getLocation(newLevel, r, c); - newLevel.map[newLocation] = tileCode; - selectedLocations.push(newLocation); - }); - clipboardData.selectedObjects.forEach(function (object) { - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(clipboardData.level, object.locations[i]); - rowcol.r += offsetR; - rowcol.c += offsetC; - if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { - // this location is oob - if (object.type === SNAKE) { - // snakes must be completely in bounds - return; - } - // just skip it - continue; - } - var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); - newLocations.push(newLocation); + var offsetR = hoverR - clipboardOffsetRowcol.r; + var offsetC = hoverC - clipboardOffsetRowcol.c; + + var newLevel = JSON.parse(JSON.stringify(level)); + var selectedLocations = []; + var selectedObjects = []; + clipboardData.selectedLocations.forEach(function(location) { + var tileCode = clipboardData.level.map[location]; + var rowcol = getRowcol(clipboardData.level, location); + var r = rowcol.r + offsetR; + var c = rowcol.c + offsetC; + if (!isInBounds(newLevel, r, c)) return; + var newLocation = getLocation(newLevel, r, c); + newLevel.map[newLocation] = tileCode; + selectedLocations.push(newLocation); + }); + clipboardData.selectedObjects.forEach(function(object) { + var newLocations = []; + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(clipboardData.level, object.locations[i]); + rowcol.r += offsetR; + rowcol.c += offsetC; + if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { + // this location is oob + if (object.type === SNAKE) { + // snakes must be completely in bounds + return; } - if (newLocations.length === 0) return; // can't have a non-present object - var newObject = JSON.parse(JSON.stringify(object)); - newObject.locations = newLocations; - selectedObjects.push(newObject); - }); - return { - level: newLevel, - selectedLocations: selectedLocations, - selectedObjects: selectedObjects, - }; + // just skip it + continue; + } + var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); + newLocations.push(newLocation); + } + if (newLocations.length === 0) return; // can't have a non-present object + var newObject = JSON.parse(JSON.stringify(object)); + newObject.locations = newLocations; + selectedObjects.push(newObject); + }); + return { + level: newLevel, + selectedLocations: selectedLocations, + selectedObjects: selectedObjects, + }; } function getNaiveOrthogonalPath(a, b) { - // does not include a, but does include b. - var rowcolA = getRowcol(level, a); - var rowcolB = getRowcol(level, b); - var path = []; - if (rowcolA.r < rowcolB.r) { - for (var r = rowcolA.r; r < rowcolB.r; r++) { - path.push(getLocation(level, r + 1, rowcolA.c)); - } - } else { - for (var r = rowcolA.r; r > rowcolB.r; r--) { - path.push(getLocation(level, r - 1, rowcolA.c)); - } + // does not include a, but does include b. + var rowcolA = getRowcol(level, a); + var rowcolB = getRowcol(level, b); + var path = []; + if (rowcolA.r < rowcolB.r) { + for (var r = rowcolA.r; r < rowcolB.r; r++) { + path.push(getLocation(level, r + 1, rowcolA.c)); } - if (rowcolA.c < rowcolB.c) { - for (var c = rowcolA.c; c < rowcolB.c; c++) { - path.push(getLocation(level, rowcolB.r, c + 1)); - } - } else { - for (var c = rowcolA.c; c > rowcolB.c; c--) { - path.push(getLocation(level, rowcolB.r, c - 1)); - } + } else { + for (var r = rowcolA.r; r > rowcolB.r; r--) { + path.push(getLocation(level, r - 1, rowcolA.c)); + } + } + if (rowcolA.c < rowcolB.c) { + for (var c = rowcolA.c; c < rowcolB.c; c++) { + path.push(getLocation(level, rowcolB.r, c + 1)); + } + } else { + for (var c = rowcolA.c; c > rowcolB.c; c--) { + path.push(getLocation(level, rowcolB.r, c - 1)); } - return path; + } + return path; } function identityFunction(x) { - return x; + return x; } function compareId(a, b) { - return operatorCompare(a.id, b.id); + return operatorCompare(a.id, b.id); } function operatorCompare(a, b) { - return a < b ? -1 : a > b ? 1 : 0; + return a < b ? -1 : a > b ? 1 : 0; } function clamp(value, min, max) { - if (value < min) return min; - if (value > max) return max; - return value; + if (value < min) return min; + if (value > max) return max; + return value; } function copyArray(array) { - return array.map(identityFunction); + return array.map(identityFunction); } function getSetIntersection(array1, array2) { - if (array1.length * array2.length === 0) return []; - return array1.filter(function (x) { return array2.indexOf(x) !== -1; }); + if (array1.length * array2.length === 0) return []; + return array1.filter(function(x) { return array2.indexOf(x) !== -1; }); } function makeScaleCoordinatesFunction(width1, width2) { - return function (location) { - return location + (width2 - width1) * Math.floor(location / width1); - }; + return function(location) { + return location + (width2 - width1) * Math.floor(location / width1); + }; } var expectHash; -window.addEventListener("hashchange", function () { - if (location.hash === expectHash) { - // We're in the middle of saveLevel() or saveReplay(). - // Don't react to that event. - expectHash = null; - return; - } - // The user typed into the url bar or used Back/Forward browser buttons, etc. - loadFromLocationHash(); +window.addEventListener("hashchange", function() { + if (location.hash === expectHash) { + // We're in the middle of saveLevel() or saveReplay(). + // Don't react to that event. + expectHash = null; + return; + } + // The user typed into the url bar or used Back/Forward browser buttons, etc. + loadFromLocationHash(); }); function loadFromLocationHash() { - var hashSegments = location.hash.split("#"); - hashSegments.shift(); // first element is always "" - if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; - var hashPairs = hashSegments.map(function (segment) { - var equalsIndex = segment.indexOf("="); - if (equalsIndex === -1) return ["", segment]; // bad - return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; - }); - - if (hashPairs[0][0] !== "level") return false; + var hashSegments = location.hash.split("#"); + hashSegments.shift(); // first element is always "" + if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; + var hashPairs = hashSegments.map(function(segment) { + var equalsIndex = segment.indexOf("="); + if (equalsIndex === -1) return ["", segment]; // bad + return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; + }); + + if (hashPairs[0][0] !== "level") return false; + try { + var level = parseLevel(hashPairs[0][1]); + } catch (e) { + alert(e); + return false; + } + loadLevel(level); + if (hashPairs.length > 1) { try { - var level = parseLevel(hashPairs[0][1]); + if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); + parseAndLoadReplay(hashPairs[1][1]); } catch (e) { - alert(e); - return false; - } - loadLevel(level); - if (hashPairs.length > 1) { - try { - if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); - parseAndLoadReplay(hashPairs[1][1]); - } catch (e) { - alert(e); - return false; - } + alert(e); + return false; } - return true; + } + return true; } // run test suite @@ -4434,5 +4418,5 @@ testTime = new Date().getTime() - testTime; loadPersistentState(); if (!loadFromLocationHash()) { - loadLevel(parseLevel(exampleLevel)); + loadLevel(parseLevel(exampleLevel)); } From 3b4a2b67d7d4b361d07171da8318ad36300560d5 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sun, 23 Feb 2020 20:34:36 -0500 Subject: [PATCH 291/577] Update Main.js --- Main.js | 7060 +++++++++++++++++++++++++++---------------------------- 1 file changed, 3529 insertions(+), 3531 deletions(-) diff --git a/Main.js b/Main.js index c59f9fb9..786d6f3b 100644 --- a/Main.js +++ b/Main.js @@ -1,7 +1,7 @@ function unreachable() { return new Error("unreachable"); } if (typeof VERSION !== "undefined") { - document.getElementById("versionSpan").innerHTML = - '' + VERSION.tag + ''; + document.getElementById("versionSpan").innerHTML = + '' + VERSION.tag + ''; } /*$(document).ready(function() { var fruits1 = getObjectsOfType(FRUIT); @@ -12,7 +12,7 @@ if (typeof VERSION !== "undefined") { }); });*/ -var img3 = document.createElement('img'); //Gooby +var img3 = document.createElement('img'); //img3.src = '/Snakefall/Snakebird Images/Cherry2.png'; var canvas = document.getElementById("canvas"); @@ -51,30 +51,30 @@ var cs = false; var tileSize = 34; var level; -var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; -var uneditStuff = {undoStack:[], redoStack:[], spanId:"editsSpan", undoButtonId:"uneditButton", redoButtonId:"reeditButton"}; +var unmoveStuff = { undoStack: [], redoStack: [], spanId: "movesSpan", undoButtonId: "unmoveButton", redoButtonId: "removeButton" }; +var uneditStuff = { undoStack: [], redoStack: [], spanId: "editsSpan", undoButtonId: "uneditButton", redoButtonId: "reeditButton" }; var paradoxes = []; function loadLevel(newLevel) { - level = newLevel; - currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); - - activateAnySnakePlease(); - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - undoStuffChanged(unmoveStuff); - uneditStuff.undoStack = []; - uneditStuff.redoStack = []; - undoStuffChanged(uneditStuff); - blockSupportRenderCache = {}; - render(); + level = newLevel; + currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); + + activateAnySnakePlease(); + unmoveStuff.undoStack = []; + unmoveStuff.redoStack = []; + undoStuffChanged(unmoveStuff); + uneditStuff.undoStack = []; + uneditStuff.redoStack = []; + undoStuffChanged(uneditStuff); + blockSupportRenderCache = {}; + render(); } var magicNumber_v0 = "3tFRIoTU"; -var magicNumber = "HyRr4JK1"; +var magicNumber = "HyRr4JK1"; var exampleLevel = magicNumber_v0 + "&" + - "17&31" + - "?" + + "17&31" + + "?" + "0000000000000000000000000000000" + "0000000000000000000000000000000" + "0000000000000000000000000000000" + @@ -92,591 +92,591 @@ var exampleLevel = magicNumber_v0 + "&" + "0000011111111101111111111100000" + "0000001111111100111111111100000" + "0000001111111000111111111100000" + - "/" + - "s0 ?351&350&349/" + - "f0 ?328/" + - "f1 ?366/"; + "/" + + "s0 ?351&350&349/" + + "f0 ?328/" + + "f1 ?366/"; var testLevel_v0 = "3tFRIoTU&5&5?0005*00300024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/"; var testLevel_v0_converted = "HyRr4JK1&5&5?0005*4024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/f0?8/"; function parseLevel(string) { - // magic number - var cursor = 0; - skipWhitespace(); - var versionTag = string.substr(cursor, magicNumber.length); - switch (versionTag) { - case magicNumber_v0: - case magicNumber: break; - default: throw new Error("not a snakefall level"); - } - cursor += magicNumber.length; - consumeKeyword("&"); - - var level = { - height: -1, - width: -1, - map: [], - objects: [], - }; - - // height, width - level.height = readInt(); - consumeKeyword("&"); - level.width = readInt(); - - // map - var mapData = readRun(); - mapData = decompressSerialization(mapData); - if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); - var upconvertedObjects = []; - var fruitCount = 0; - var tileCounter = 0; - for (var i = 0; i < mapData.length; i++) { - var tileCode = mapData[i].charCodeAt(0); - if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { - // fruit used to be a tile code. now it's an object. - upconvertedObjects.push({ - type: FRUIT, - id: fruitCount++, - dead: false, // unused - locations: [i], - }); - tileCode = SPACE; + // magic number + var cursor = 0; + skipWhitespace(); + var versionTag = string.substr(cursor, magicNumber.length); + switch (versionTag) { + case magicNumber_v0: + case magicNumber: break; + default: throw new Error("not a snakefall level"); } - if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; - if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); - level.map.push(tileCode); - } - - // objects - skipWhitespace(); - while (cursor < string.length) { - var object = { - type: "?", - id: -1, - dead: false, - locations: [], + cursor += magicNumber.length; + consumeKeyword("&"); + + var level = { + height: -1, + width: -1, + map: [], + objects: [], }; - // type - object.type = string[cursor]; - var locationsLimit; - if (object.type === SNAKE) locationsLimit = -1; - else if (object.type === BLOCK) locationsLimit = -1; - else if (object.type === FRUIT || object.type === POISON_FRUIT) locationsLimit = 1; - else throw parserError("expected object type code"); - cursor += 1; - - // id - object.id = readInt(); - - // locations - var locationsData = readRun(); - var locationStrings = locationsData.split("&"); - if (locationStrings.length === 0) throw parserError("locations must be non-empty"); - if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); - - locationStrings.forEach(function(locationString) { - var location = parseInt(locationString); - if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); - object.locations.push(location); - }); + // height, width + level.height = readInt(); + consumeKeyword("&"); + level.width = readInt(); + + // map + var mapData = readRun(); + mapData = decompressSerialization(mapData); + if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); + var upconvertedObjects = []; + var fruitCount = 0; + var tileCounter = 0; + for (var i = 0; i < mapData.length; i++) { + var tileCode = mapData[i].charCodeAt(0); + if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { + // fruit used to be a tile code. now it's an object. + upconvertedObjects.push({ + type: FRUIT, + id: fruitCount++, + dead: false, // unused + locations: [i], + }); + tileCode = SPACE; + } + if (tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; + if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); + level.map.push(tileCode); + } - level.objects.push(object); + // objects skipWhitespace(); - } - - if(tileCounter>0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL
    contains experimental elements"; + while (cursor < string.length) { + var object = { + type: "?", + id: -1, + dead: false, + locations: [], + }; + + // type + object.type = string[cursor]; + var locationsLimit; + if (object.type === SNAKE) locationsLimit = -1; + else if (object.type === BLOCK) locationsLimit = -1; + else if (object.type === FRUIT || object.type === POISON_FRUIT) locationsLimit = 1; + else throw parserError("expected object type code"); + cursor += 1; + + // id + object.id = readInt(); + + // locations + var locationsData = readRun(); + var locationStrings = locationsData.split("&"); + if (locationStrings.length === 0) throw parserError("locations must be non-empty"); + if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); + + locationStrings.forEach(function (locationString) { + var location = parseInt(locationString); + if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); + object.locations.push(location); + }); + + level.objects.push(object); + skipWhitespace(); + } + + if (tileCounter > 0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL
    contains experimental elements"; else document.getElementById("levelType").innerHTML = "STANDARD LEVEL
    does not contain experimental elements"; - - for (var i = 0; i < upconvertedObjects.length; i++) { - level.objects.push(upconvertedObjects[i]); - } - return level; + for (var i = 0; i < upconvertedObjects.length; i++) { + level.objects.push(upconvertedObjects[i]); + } + + return level; - function skipWhitespace() { - while (" \n\t\r".indexOf(string[cursor]) !== -1) { - cursor += 1; + function skipWhitespace() { + while (" \n\t\r".indexOf(string[cursor]) !== -1) { + cursor += 1; + } } - } - function consumeKeyword(keyword) { - skipWhitespace(); - if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); - cursor += 1; - } - function readInt() { - skipWhitespace(); - for (var i = cursor; i < string.length; i++) { - if ("0123456789".indexOf(string[i]) === -1) break; + function consumeKeyword(keyword) { + skipWhitespace(); + if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); + cursor += 1; + } + function readInt() { + skipWhitespace(); + for (var i = cursor; i < string.length; i++) { + if ("0123456789".indexOf(string[i]) === -1) break; + } + var substring = string.substring(cursor, i); + if (substring.length === 0) throw parserError("expected int"); + cursor = i; + return parseInt(substring, 10); + } + function readRun() { + consumeKeyword("?"); + var endIndex = string.indexOf("/", cursor); + var substring = string.substring(cursor, endIndex); + cursor = endIndex + 1; + return substring; + } + function parserError(message) { + return new Error("parse error at position " + cursor + ": " + message); } - var substring = string.substring(cursor, i); - if (substring.length === 0) throw parserError("expected int"); - cursor = i; - return parseInt(substring, 10); - } - function readRun() { - consumeKeyword("?"); - var endIndex = string.indexOf("/", cursor); - var substring = string.substring(cursor, endIndex); - cursor = endIndex + 1; - return substring; - } - function parserError(message) { - return new Error("parse error at position " + cursor + ": " + message); - } } function serializeTileCode(tileCode) { - return String.fromCharCode(tileCode); + return String.fromCharCode(tileCode); } function stringifyLevel(level) { - var output = magicNumber + "&"; - output += level.height + "&" + level.width + "\n"; + var output = magicNumber + "&"; + output += level.height + "&" + level.width + "\n"; - output += "?\n"; - for (var r = 0; r < level.height; r++) { - output += " " + level.map.slice(r * level.width, (r + 1) * level.width).map(serializeTileCode).join("") + "\n"; - } - output += "/\n"; + output += "?\n"; + for (var r = 0; r < level.height; r++) { + output += " " + level.map.slice(r * level.width, (r + 1) * level.width).map(serializeTileCode).join("") + "\n"; + } + output += "/\n"; - output += serializeObjects(level.objects); + output += serializeObjects(level.objects); - // sanity check - var shouldBeTheSame = parseLevel(output); - if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken + // sanity check + var shouldBeTheSame = parseLevel(output); + if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken - return output; + return output; } function serializeObjects(objects) { - var output = ""; - for (var i = 0; i < objects.length; i++) { - var object = objects[i]; - output += object.type + object.id + " "; - output += "?" + object.locations.join("&") + "/\n"; - } - return output; + var output = ""; + for (var i = 0; i < objects.length; i++) { + var object = objects[i]; + output += object.type + object.id + " "; + output += "?" + object.locations.join("&") + "/\n"; + } + return output; } function serializeObjectState(object) { - if (object == null) return [0,[]]; - return [object.dead, copyArray(object.locations)]; + if (object == null) return [0, []]; + return [object.dead, copyArray(object.locations)]; } var base66 = "----0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; function compressSerialization(string) { - string = string.replace(/\s+/g, ""); - // run-length encode several 0's in a row, etc. - // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) - var result = ""; - var runStart = 0; - for (var i = 1; i < string.length + 1; i++) { - var runLength = i - runStart; - if (string[i] === string[runStart] && runLength < base66.length - 1) continue; - // end of run - if (runLength >= 4) { - // compress - result += "*" + base66[runLength] + string[runStart]; - } else { - // literal - result += string.substring(runStart, i); + string = string.replace(/\s+/g, ""); + // run-length encode several 0's in a row, etc. + // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) + var result = ""; + var runStart = 0; + for (var i = 1; i < string.length + 1; i++) { + var runLength = i - runStart; + if (string[i] === string[runStart] && runLength < base66.length - 1) continue; + // end of run + if (runLength >= 4) { + // compress + result += "*" + base66[runLength] + string[runStart]; + } else { + // literal + result += string.substring(runStart, i); + } + runStart = i; } - runStart = i; - } - return result; + return result; } function decompressSerialization(string) { - string = string.replace(/\s+/g, ""); - var result = ""; - for (var i = 0; i < string.length; i++) { - if (string[i] === "*") { - i += 1; - var runLength = base66.indexOf(string[i]); - i += 1; - var char = string[i]; - for (var j = 0; j < runLength; j++) { - result += char; - } - } else { - result += string[i]; + string = string.replace(/\s+/g, ""); + var result = ""; + for (var i = 0; i < string.length; i++) { + if (string[i] === "*") { + i += 1; + var runLength = base66.indexOf(string[i]); + i += 1; + var char = string[i]; + for (var j = 0; j < runLength; j++) { + result += char; + } + } else { + result += string[i]; + } } - } - return result; + return result; } var replayMagicNumber = "nmGTi8PB"; function stringifyReplay() { - var output = replayMagicNumber + "&"; - // only specify the snake id in an input if it's different from the previous. - // the first snake index is 0 to optimize for the single-snake case. - var currentSnakeId = 0; - for (var i = 0; i < unmoveStuff.undoStack.length; i++) { - var firstChange = unmoveStuff.undoStack[i][0]; - if (firstChange[0] !== "i") throw unreachable(); - var snakeId = firstChange[1]; - var dr = firstChange[2]; - var dc = firstChange[3]; - var directionCode; - if (dr ===-1 && dc === 0) directionCode = "u"; - else if (dr === 0 && dc ===-1) directionCode = "l"; - else if (dr === 1 && dc === 0) directionCode = "d"; - else if (dr === 0 && dc === 1) directionCode = "r"; - else throw unreachable(); - if (snakeId !== currentSnakeId) { - output += snakeId; // int to string - currentSnakeId = snakeId; + var output = replayMagicNumber + "&"; + // only specify the snake id in an input if it's different from the previous. + // the first snake index is 0 to optimize for the single-snake case. + var currentSnakeId = 0; + for (var i = 0; i < unmoveStuff.undoStack.length; i++) { + var firstChange = unmoveStuff.undoStack[i][0]; + if (firstChange[0] !== "i") throw unreachable(); + var snakeId = firstChange[1]; + var dr = firstChange[2]; + var dc = firstChange[3]; + var directionCode; + if (dr === -1 && dc === 0) directionCode = "u"; + else if (dr === 0 && dc === -1) directionCode = "l"; + else if (dr === 1 && dc === 0) directionCode = "d"; + else if (dr === 0 && dc === 1) directionCode = "r"; + else throw unreachable(); + if (snakeId !== currentSnakeId) { + output += snakeId; // int to string + currentSnakeId = snakeId; + } + output += directionCode; } - output += directionCode; - } - return output; + return output; } function parseAndLoadReplay(string) { - string = decompressSerialization(string); - var expectedPrefix = replayMagicNumber + "&"; - if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); - var cursor = expectedPrefix.length; - - // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. - activeSnakeId = 0; - while (cursor < string.length) { - var snakeIdStr = ""; - var c = string.charAt(cursor); - cursor += 1; - while ('0' <= c && c <= '9') { - snakeIdStr += c; - if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); - c = string.charAt(cursor); - cursor += 1; - } - if (snakeIdStr.length > 0) { - activeSnakeId = parseInt(snakeIdStr); - // don't just validate when switching snakes, but on every move. - } + string = decompressSerialization(string); + var expectedPrefix = replayMagicNumber + "&"; + if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); + var cursor = expectedPrefix.length; + + // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. + activeSnakeId = 0; + while (cursor < string.length) { + var snakeIdStr = ""; + var c = string.charAt(cursor); + cursor += 1; + while ('0' <= c && c <= '9') { + snakeIdStr += c; + if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); + c = string.charAt(cursor); + cursor += 1; + } + if (snakeIdStr.length > 0) { + activeSnakeId = parseInt(snakeIdStr); + // don't just validate when switching snakes, but on every move. + } - // doing a move. - if (!getSnakes().some(function(snake) { - return snake.id === activeSnakeId; - })) { - throw new Error("invalid snake id: " + activeSnakeId); - } - switch (c) { - case 'l': move( 0, -1); break; - case 'u': move(-1, 0); break; - case 'r': move( 0, 1); break; - case 'd': move( 1, 0); break; - default: throw new Error("replay string has invalid direction: " + c); + // doing a move. + if (!getSnakes().some(function (snake) { + return snake.id === activeSnakeId; + })) { + throw new Error("invalid snake id: " + activeSnakeId); + } + switch (c) { + case 'l': move(0, -1); break; + case 'u': move(-1, 0); break; + case 'r': move(0, 1); break; + case 'd': move(1, 0); break; + default: throw new Error("replay string has invalid direction: " + c); + } } - } - // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. - reset(unmoveStuff); - document.getElementById("removeButton").classList.add("click-me"); + // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. + reset(unmoveStuff); + document.getElementById("removeButton").classList.add("click-me"); } var currentSerializedLevel; function saveLevel() { - if (isDead()) return alert("Can't save while you're dead!"); - var serializedLevel = compressSerialization(stringifyLevel(level)); - currentSerializedLevel = serializedLevel; - var hash = "#level=" + serializedLevel; - expectHash = hash; - location.hash = hash; - - // This marks a starting point for solving the level. - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - editorHasBeenTouched = false; - undoStuffChanged(unmoveStuff); + if (isDead()) return alert("Can't save while you're dead!"); + var serializedLevel = compressSerialization(stringifyLevel(level)); + currentSerializedLevel = serializedLevel; + var hash = "#level=" + serializedLevel; + expectHash = hash; + location.hash = hash; + + // This marks a starting point for solving the level. + unmoveStuff.undoStack = []; + unmoveStuff.redoStack = []; + editorHasBeenTouched = false; + undoStuffChanged(unmoveStuff); } function saveReplay() { - if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); - // preserve the level in the url bar. - var hash = "#level=" + currentSerializedLevel; - if (dirtyState === REPLAY_DIRTY) { - // there is a replay to save - hash += "#replay=" + compressSerialization(stringifyReplay()); - } - expectHash = hash; - location.hash = hash; + if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); + // preserve the level in the url bar. + var hash = "#level=" + currentSerializedLevel; + if (dirtyState === REPLAY_DIRTY) { + // there is a replay to save + hash += "#replay=" + compressSerialization(stringifyReplay()); + } + expectHash = hash; + location.hash = hash; } function deepEquals(a, b) { - if (a == null) return b == null; - if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; - if (Array.isArray(a)) { - if (!Array.isArray(b)) return false; - if (a.length !== b.length) return false; - for (var i = 0; i < a.length; i++) { - if (!deepEquals(a[i], b[i])) return false; + if (a == null) return b == null; + if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; + if (Array.isArray(a)) { + if (!Array.isArray(b)) return false; + if (a.length !== b.length) return false; + for (var i = 0; i < a.length; i++) { + if (!deepEquals(a[i], b[i])) return false; + } + return true; + } + // must be objects + var aKeys = Object.keys(a); + var bKeys = Object.keys(b); + if (aKeys.length !== bKeys.length) return false; + aKeys.sort(); + bKeys.sort(); + if (!deepEquals(aKeys, bKeys)) return false; + for (var i = 0; i < aKeys.length; i++) { + if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; } return true; - } - // must be objects - var aKeys = Object.keys(a); - var bKeys = Object.keys(b); - if (aKeys.length !== bKeys.length) return false; - aKeys.sort(); - bKeys.sort(); - if (!deepEquals(aKeys, bKeys)) return false; - for (var i = 0; i < aKeys.length; i++) { - if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; - } - return true; } function getLocation(level, r, c) { - if (!isInBounds(level, r, c)) throw unreachable(); - return r * level.width + c; + if (!isInBounds(level, r, c)) throw unreachable(); + return r * level.width + c; } function getRowcol(level, location) { - if (location < 0 || location >= level.width * level.height) throw unreachable(); - var r = Math.floor(location / level.width); - var c = location % level.width; - return {r:r, c:c}; + if (location < 0 || location >= level.width * level.height) throw unreachable(); + var r = Math.floor(location / level.width); + var c = location % level.width; + return { r: r, c: c }; } function isInBounds(level, r, c) { - if (c < 0 || c >= level.width) return false;; - if (r < 0 || r >= level.height) return false;; - return true; + if (c < 0 || c >= level.width) return false;; + if (r < 0 || r >= level.height) return false;; + return true; } function offsetLocation(location, dr, dc) { - var rowcol = getRowcol(level, location); - return getLocation(level, rowcol.r + dr, rowcol.c + dc); + var rowcol = getRowcol(level, location); + return getLocation(level, rowcol.r + dr, rowcol.c + dc); } var SHIFT = 1; var CTRL = 2; var ALT = 4; -document.addEventListener("keydown", function(event) { - var modifierMask = ( - (event.shiftKey ? SHIFT : 0) | - (event.ctrlKey ? CTRL : 0) | - (event.altKey ? ALT : 0) - ); - switch (event.keyCode) { - case 37: // left - if (modifierMask === 0) { move(0, -1); break; } - return; - case 38: // up - if (modifierMask === 0) { move(-1, 0); break; } - return; - case 39: // right - if (modifierMask === 0) { move(0, 1); break; } - return; - case 40: // down - if (modifierMask === 0) { move(1, 0); break; } - return; - case 8: // backspace - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Q".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - return; - case "Z".charCodeAt(0): - if (modifierMask === 0) { undo(unmoveStuff); break; } - if (modifierMask === SHIFT) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { undo(uneditStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL|SHIFT) { redo(uneditStuff); break; } - return; - case "Y".charCodeAt(0): - if (modifierMask === 0) { redo(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { redo(uneditStuff); break; } - return; - case "R".charCodeAt(0): - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } - if (modifierMask === 0) { reset(unmoveStuff); break; } - if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLR); break; } - return; - case 220: // backslash - if (modifierMask === 0) { toggleShowEditor(); break; } - return; - case "A".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, -1); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PORTAL); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { selectAll(); break; } - return; - case "E".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(EXIT); break; } - return; - case 46: // delete - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } - return; - case "W".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(WOODPLATFORM); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(WATER); break; } - return; - case "S".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPIKE); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(SNAKE); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { saveLevel(); break; } - if (!persistentState.showEditor && modifierMask === CTRL) { saveReplay(); break; } - if (modifierMask === (CTRL|SHIFT)) { saveReplay(); break; } - return; - case "X".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } - return; - case "F".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(POISON_FRUIT); break; } - return; - case "D".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLD); break; } - return; - case "B".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(BUBBLE); break; } - return; - case "P".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } - return; - case "U".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLU); break; } - return; - case "L".charCodeAt(0): - if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOSEDLIFT); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(OPENLIFT); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLL); break; } - return; - case "G".charCodeAt(0): - if (modifierMask === 0) { toggleGrid(); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } - return; - case "C".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } - if ( persistentState.showEditor && modifierMask === SHIFT) { toggleCollision(); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } - return; - case "V".charCodeAt(0): - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(LAVA); break; } - if ( persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } - case "T".charCodeAt(0): - toggleTheme(); break; - return; - case 32: // spacebar - case 9: // tab - if (modifierMask === 0) { switchSnakes( 1); break; } - if (modifierMask === SHIFT) { switchSnakes(-1); break; } - return; - case "1".charCodeAt(0): - case "2".charCodeAt(0): - case "3".charCodeAt(0): - case "4".charCodeAt(0): - var index = event.keyCode - "1".charCodeAt(0); - var delta; - if (modifierMask === 0) { - delta = 1; - } else if (modifierMask === SHIFT) { - delta = -1; - } else return; - if (isAlive()) { - (function() { - var snakes = findSnakesOfColor(index); - if (snakes.length === 0) return; - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; +document.addEventListener("keydown", function (event) { + var modifierMask = ( + (event.shiftKey ? SHIFT : 0) | + (event.ctrlKey ? CTRL : 0) | + (event.altKey ? ALT : 0) + ); + switch (event.keyCode) { + case 37: // left + if (modifierMask === 0) { move(0, -1); break; } + return; + case 38: // up + if (modifierMask === 0) { move(-1, 0); break; } + return; + case 39: // right + if (modifierMask === 0) { move(0, 1); break; } + return; + case 40: // down + if (modifierMask === 0) { move(1, 0); break; } + return; + case 8: // backspace + if (modifierMask === 0) { undo(unmoveStuff); break; } + if (modifierMask === SHIFT) { redo(unmoveStuff); break; } + return; + case "Q".charCodeAt(0): + if (modifierMask === 0) { undo(unmoveStuff); break; } + if (modifierMask === SHIFT) { redo(unmoveStuff); break; } + return; + case "Z".charCodeAt(0): + if (modifierMask === 0) { undo(unmoveStuff); break; } + if (modifierMask === SHIFT) { redo(unmoveStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL) { undo(uneditStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL | SHIFT) { redo(uneditStuff); break; } + return; + case "Y".charCodeAt(0): + if (modifierMask === 0) { redo(unmoveStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL) { redo(uneditStuff); break; } + return; + case "R".charCodeAt(0): + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } + if (modifierMask === 0) { reset(unmoveStuff); break; } + if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } + if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLR); break; } + return; + case 220: // backslash + if (modifierMask === 0) { toggleShowEditor(); break; } + return; + case "A".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(0, -1); break; } + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PORTAL); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("select"); break; } + if (persistentState.showEditor && modifierMask === CTRL) { selectAll(); break; } + return; + case "E".charCodeAt(0): + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(EXIT); break; } + return; + case 46: // delete + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPACE); break; } + return; + case "W".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(WOODPLATFORM); break; } + if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(WATER); break; } + return; + case "S".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(SPIKE); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(SNAKE); break; } + if (persistentState.showEditor && modifierMask === CTRL) { saveLevel(); break; } + if (!persistentState.showEditor && modifierMask === CTRL) { saveReplay(); break; } + if (modifierMask === (CTRL | SHIFT)) { saveReplay(); break; } + return; + case "X".charCodeAt(0): + if (persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } + return; + case "F".charCodeAt(0): + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(POISON_FRUIT); break; } + return; + case "D".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } + if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLD); break; } + return; + case "B".charCodeAt(0): + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(BUBBLE); break; } + return; + case "P".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } + return; + case "U".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLU); break; } + return; + case "L".charCodeAt(0): + if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOSEDLIFT); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(OPENLIFT); break; } + if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLL); break; } + return; + case "G".charCodeAt(0): + if (modifierMask === 0) { toggleGrid(); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { toggleGravity(); break; } + return; + case "C".charCodeAt(0): + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOUD); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { toggleCollision(); break; } + if (persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } + return; + case "V".charCodeAt(0): + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(LAVA); break; } + if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } + case "T".charCodeAt(0): + toggleTheme(); break; + return; + case 32: // spacebar + case 9: // tab + if (modifierMask === 0) { switchSnakes(1); break; } + if (modifierMask === SHIFT) { switchSnakes(-1); break; } + return; + case "1".charCodeAt(0): + case "2".charCodeAt(0): + case "3".charCodeAt(0): + case "4".charCodeAt(0): + var index = event.keyCode - "1".charCodeAt(0); + var delta; + if (modifierMask === 0) { + delta = 1; + } else if (modifierMask === SHIFT) { + delta = -1; + } else return; + if (isAlive()) { + (function () { + var snakes = findSnakesOfColor(index); + if (snakes.length === 0) return; + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) { + activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; + return; + } + } + activeSnakeId = snakes[0].id; + })(); } - } - activeSnakeId = snakes[0].id; - })(); - } - break; - case 27: // escape - if ( persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(null); break; } - return; - default: return; - } - event.preventDefault(); - render(); + break; + case 27: // escape + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(null); break; } + return; + default: return; + } + event.preventDefault(); + render(); }); -document.getElementById("switchSnakesButton").addEventListener("click", function() { - switchSnakes(1); - render(); +document.getElementById("switchSnakesButton").addEventListener("click", function () { + switchSnakes(1); + render(); }); function switchSnakes(delta) { - if (!isAlive()) return; - var snakes = getSnakes(); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) { - activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; - return; + if (!isAlive()) return; + var snakes = getSnakes(); + snakes.sort(compareId); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) { + activeSnakeId = snakes[(i + delta + snakes.length) % snakes.length].id; + return; + } } - } - activeSnakeId = snakes[0].id; + activeSnakeId = snakes[0].id; } -document.getElementById("showGridButton").addEventListener("click", function() { - toggleGrid(); +document.getElementById("showGridButton").addEventListener("click", function () { + toggleGrid(); }); -document.getElementById("saveProgressButton").addEventListener("click", function() { - saveReplay(); +document.getElementById("saveProgressButton").addEventListener("click", function () { + saveReplay(); }); -document.getElementById("checkSolutionButton").addEventListener("click", function() { - redoAll(unmoveStuff); +document.getElementById("checkSolutionButton").addEventListener("click", function () { + redoAll(unmoveStuff); }); -document.getElementById("restartButton").addEventListener("click", function() { - reset(unmoveStuff); - render(); +document.getElementById("restartButton").addEventListener("click", function () { + reset(unmoveStuff); + render(); }); -document.getElementById("unmoveButton").addEventListener("click", function() { - undo(unmoveStuff); - render(); +document.getElementById("unmoveButton").addEventListener("click", function () { + undo(unmoveStuff); + render(); }); -document.getElementById("removeButton").addEventListener("click", function() { - redo(unmoveStuff); - render(); +document.getElementById("removeButton").addEventListener("click", function () { + redo(unmoveStuff); + render(); }); -document.getElementById("showHideEditor").addEventListener("click", function() { - toggleShowEditor(); +document.getElementById("showHideEditor").addEventListener("click", function () { + toggleShowEditor(); }); function toggleShowEditor() { - persistentState.showEditor = !persistentState.showEditor; - savePersistentState(); - showEditorChanged(); + persistentState.showEditor = !persistentState.showEditor; + savePersistentState(); + showEditorChanged(); } function toggleGrid() { - persistentState.showGrid = !persistentState.showGrid; - savePersistentState(); - render(); + persistentState.showGrid = !persistentState.showGrid; + savePersistentState(); + render(); } -["serializationTextarea", "shareLinkTextbox"].forEach(function(id) { - document.getElementById(id).addEventListener("keydown", function(event) { - // let things work normally - event.stopPropagation(); - }); +["serializationTextarea", "shareLinkTextbox"].forEach(function (id) { + document.getElementById(id).addEventListener("keydown", function (event) { + // let things work normally + event.stopPropagation(); + }); }); -document.getElementById("submitSerializationButton").addEventListener("click", function() { - var string = document.getElementById("serializationTextarea").value; - try { - var newLevel = parseLevel(string); - } catch (e) { - alert(e); - return; - } - loadLevel(newLevel); +document.getElementById("submitSerializationButton").addEventListener("click", function () { + var string = document.getElementById("serializationTextarea").value; + try { + var newLevel = parseLevel(string); + } catch (e) { + alert(e); + return; + } + loadLevel(newLevel); }); -document.getElementById("shareLinkTextbox").addEventListener("focus", function() { - setTimeout(function() { - document.getElementById("shareLinkTextbox").select(); - }, 0); +document.getElementById("shareLinkTextbox").addEventListener("focus", function () { + setTimeout(function () { + document.getElementById("shareLinkTextbox").select(); + }, 0); }); var paintBrushTileCode = null; @@ -689,765 +689,765 @@ var resizeDragAnchorRowcol = null; var clipboardData = null; var clipboardOffsetRowcol = null; var paintButtonIdAndTileCodes = [ - ["resizeButton", "resize"], - ["selectButton", "select"], - ["pasteButton", "paste"], - ["paintSpaceButton", SPACE], - ["paintWallButton", WALL], - ["paintSpikeButton", SPIKE], - ["paintExitButton", EXIT], - ["paintFruitButton", FRUIT], - ["paintPoisonFruitButton", POISON_FRUIT], - ["paintPortalButton", PORTAL], - ["paintPlatformButton", PLATFORM], - ["paintWoodPlatformButton", WOODPLATFORM], - ["paintOneWayWallUButton", ONEWAYWALLU], - ["paintOneWayWallDButton", ONEWAYWALLD], - ["paintOneWayWallLButton", ONEWAYWALLL], - ["paintOneWayWallRButton", ONEWAYWALLR], - ["paintClosedLiftButton", CLOSEDLIFT], - ["paintOpenLiftButton", OPENLIFT], - ["paintCloudButton", CLOUD], - ["paintBubbleButton", BUBBLE], - ["paintLavaButton", LAVA], - ["paintWaterButton", WATER], - ["paintSnakeButton", SNAKE], - ["paintBlockButton", BLOCK], + ["resizeButton", "resize"], + ["selectButton", "select"], + ["pasteButton", "paste"], + ["paintSpaceButton", SPACE], + ["paintWallButton", WALL], + ["paintSpikeButton", SPIKE], + ["paintExitButton", EXIT], + ["paintFruitButton", FRUIT], + ["paintPoisonFruitButton", POISON_FRUIT], + ["paintPortalButton", PORTAL], + ["paintPlatformButton", PLATFORM], + ["paintWoodPlatformButton", WOODPLATFORM], + ["paintOneWayWallUButton", ONEWAYWALLU], + ["paintOneWayWallDButton", ONEWAYWALLD], + ["paintOneWayWallLButton", ONEWAYWALLL], + ["paintOneWayWallRButton", ONEWAYWALLR], + ["paintClosedLiftButton", CLOSEDLIFT], + ["paintOpenLiftButton", OPENLIFT], + ["paintCloudButton", CLOUD], + ["paintBubbleButton", BUBBLE], + ["paintLavaButton", LAVA], + ["paintWaterButton", WATER], + ["paintSnakeButton", SNAKE], + ["paintBlockButton", BLOCK], ]; -paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - document.getElementById(id).addEventListener("click", function() { - setPaintBrushTileCode(tileCode); - }); +paintButtonIdAndTileCodes.forEach(function (pair) { + var id = pair[0]; + var tileCode = pair[1]; + document.getElementById(id).addEventListener("click", function () { + setPaintBrushTileCode(tileCode); + }); }); -document.getElementById("uneditButton").addEventListener("click", function() { - undo(uneditStuff); - render(); +document.getElementById("uneditButton").addEventListener("click", function () { + undo(uneditStuff); + render(); }); -document.getElementById("reeditButton").addEventListener("click", function() { - redo(uneditStuff); - render(); +document.getElementById("reeditButton").addEventListener("click", function () { + redo(uneditStuff); + render(); }); -document.getElementById("saveLevelButton").addEventListener("click", function() { - saveLevel(); +document.getElementById("saveLevelButton").addEventListener("click", function () { + saveLevel(); }); -document.getElementById("copyButton").addEventListener("click", function() { - copySelection(); +document.getElementById("copyButton").addEventListener("click", function () { + copySelection(); }); -document.getElementById("cutButton").addEventListener("click", function() { - cutSelection(); +document.getElementById("cutButton").addEventListener("click", function () { + cutSelection(); }); -document.getElementById("cheatGravityButton").addEventListener("click", function() { - toggleGravity(); +document.getElementById("cheatGravityButton").addEventListener("click", function () { + toggleGravity(); }); -document.getElementById("cheatCollisionButton").addEventListener("click", function() { - toggleCollision(); +document.getElementById("cheatCollisionButton").addEventListener("click", function () { + toggleCollision(); }); -document.getElementById("themeButton").addEventListener("click", function() { - toggleTheme(); +document.getElementById("themeButton").addEventListener("click", function () { + toggleTheme(); }); function toggleTheme() { - if(themeCounter"; } function toggleGravity() { - isGravityEnabled = !isGravityEnabled; - isCollisionEnabled = true; - refreshCheatButtonText(); + isGravityEnabled = !isGravityEnabled; + isCollisionEnabled = true; + refreshCheatButtonText(); } function toggleCollision() { - isCollisionEnabled = !isCollisionEnabled; - isGravityEnabled = false; - refreshCheatButtonText(); + isCollisionEnabled = !isCollisionEnabled; + isGravityEnabled = false; + refreshCheatButtonText(); } function refreshCheatButtonText() { - document.getElementById("cheatGravityButton").textContent = isGravityEnabled ? "Gravity: ON" : "Gravity: OFF"; - document.getElementById("cheatGravityButton").style.background = isGravityEnabled ? "" : "#f88"; + document.getElementById("cheatGravityButton").textContent = isGravityEnabled ? "Gravity: ON" : "Gravity: OFF"; + document.getElementById("cheatGravityButton").style.background = isGravityEnabled ? "" : "#f88"; - document.getElementById("cheatCollisionButton").textContent = isCollisionEnabled ? "Collision: ON" : "Collision: OFF"; - document.getElementById("cheatCollisionButton").style.background = isCollisionEnabled ? "" : "#f88"; + document.getElementById("cheatCollisionButton").textContent = isCollisionEnabled ? "Collision: ON" : "Collision: OFF"; + document.getElementById("cheatCollisionButton").style.background = isCollisionEnabled ? "" : "#f88"; } // be careful with location vs rowcol, because this variable is used when resizing var lastDraggingRowcol = null; var hoverLocation = null; var draggingChangeLog = null; -canvas.addEventListener("mousedown", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - var location = getLocationFromEvent(event); - if (persistentState.showEditor && paintBrushTileCode != null) { - // editor tool - lastDraggingRowcol = getRowcol(level, location); - if (paintBrushTileCode === "select") selectionStart = location; - if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; - draggingChangeLog = []; - paintAtLocation(location, draggingChangeLog); - } else { - // playtime - var object = findObjectAtLocation(location); - if (object == null) return; - if (object.type !== SNAKE) return; - // active snake - activeSnakeId = object.id; - render(); - } -}); -canvas.addEventListener("dblclick", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - if (persistentState.showEditor && paintBrushTileCode === "select") { - // double click with select tool +canvas.addEventListener("mousedown", function (event) { + if (event.altKey) return; + if (event.button !== 0) return; + event.preventDefault(); var location = getLocationFromEvent(event); - var object = findObjectAtLocation(location); - if (object == null) return; - stopDragging(); - if (object.type === SNAKE) { - // edit snakes of this color - paintBrushTileCode = SNAKE; - paintBrushSnakeColorIndex = object.id % snakeColors.length; - } else if (object.type === BLOCK) { - // edit this particular block - paintBrushTileCode = BLOCK; - paintBrushBlockId = object.id; - } else if (object.type === FRUIT) { - // edit fruits, i guess - paintBrushTileCode = FRUIT; - } else if (object.type === POISON_FRUIT) { - // edit poison fruits, i guess - paintBrushTileCode = POISON_FRUIT; + if (persistentState.showEditor && paintBrushTileCode != null) { + // editor tool + lastDraggingRowcol = getRowcol(level, location); + if (paintBrushTileCode === "select") selectionStart = location; + if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; + draggingChangeLog = []; + paintAtLocation(location, draggingChangeLog); + } else { + // playtime + var object = findObjectAtLocation(location); + if (object == null) return; + if (object.type !== SNAKE) return; + // active snake + activeSnakeId = object.id; + render(); } - else throw unreachable(); - paintBrushTileCodeChanged(); - } }); -document.addEventListener("mouseup", function(event) { - stopDragging(); +canvas.addEventListener("dblclick", function (event) { + if (event.altKey) return; + if (event.button !== 0) return; + event.preventDefault(); + if (persistentState.showEditor && paintBrushTileCode === "select") { + // double click with select tool + var location = getLocationFromEvent(event); + var object = findObjectAtLocation(location); + if (object == null) return; + stopDragging(); + if (object.type === SNAKE) { + // edit snakes of this color + paintBrushTileCode = SNAKE; + paintBrushSnakeColorIndex = object.id % snakeColors.length; + } else if (object.type === BLOCK) { + // edit this particular block + paintBrushTileCode = BLOCK; + paintBrushBlockId = object.id; + } else if (object.type === FRUIT) { + // edit fruits, i guess + paintBrushTileCode = FRUIT; + } else if (object.type === POISON_FRUIT) { + // edit poison fruits, i guess + paintBrushTileCode = POISON_FRUIT; + } + else throw unreachable(); + paintBrushTileCodeChanged(); + } +}); +document.addEventListener("mouseup", function (event) { + stopDragging(); }); function stopDragging() { - if (lastDraggingRowcol != null) { - // release the draggin' - lastDraggingRowcol = null; - paintBrushObject = null; - resizeDragAnchorRowcol = null; - pushUndo(uneditStuff, draggingChangeLog); - draggingChangeLog = null; - } + if (lastDraggingRowcol != null) { + // release the draggin' + lastDraggingRowcol = null; + paintBrushObject = null; + resizeDragAnchorRowcol = null; + pushUndo(uneditStuff, draggingChangeLog); + draggingChangeLog = null; + } } -canvas.addEventListener("mousemove", function(event) { - if (!persistentState.showEditor) return; - var location = getLocationFromEvent(event); - var mouseRowcol = getRowcol(level, location); - if (lastDraggingRowcol != null) { - // Dragging Force - Through the Fruit and Flames - var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); - // we need to get rowcols for everything before we start dragging, because dragging might resize the world. - var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function(location) { - return getRowcol(level, location); - }); - path.forEach(function(rowcol) { - // convert to location at the last minute in case each of these steps is changing the coordinate system. - paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); - }); - lastDraggingRowcol = mouseRowcol; - hoverLocation = null; - } else { - // hovering - if (hoverLocation !== location) { - hoverLocation = location; - render(); +canvas.addEventListener("mousemove", function (event) { + if (!persistentState.showEditor) return; + var location = getLocationFromEvent(event); + var mouseRowcol = getRowcol(level, location); + if (lastDraggingRowcol != null) { + // Dragging Force - Through the Fruit and Flames + var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); + // we need to get rowcols for everything before we start dragging, because dragging might resize the world. + var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function (location) { + return getRowcol(level, location); + }); + path.forEach(function (rowcol) { + // convert to location at the last minute in case each of these steps is changing the coordinate system. + paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); + }); + lastDraggingRowcol = mouseRowcol; + hoverLocation = null; + } else { + // hovering + if (hoverLocation !== location) { + hoverLocation = location; + render(); + } } - } }); -canvas.addEventListener("mouseout", function() { - if (hoverLocation !== location) { - // turn off the hover when the mouse leaves - hoverLocation = null; - render(); - } +canvas.addEventListener("mouseout", function () { + if (hoverLocation !== location) { + // turn off the hover when the mouse leaves + hoverLocation = null; + render(); + } }); function getLocationFromEvent(event) { - var r = Math.floor(eventToMouseY(event, canvas) / tileSize); - var c = Math.floor(eventToMouseX(event, canvas) / tileSize); - // since the canvas is centered, the bounding client rect can be half-pixel aligned, - // resulting in slightly out-of-bounds mouse events. - r = clamp(r, 0, level.height); - c = clamp(c, 0, level.width); - return getLocation(level, r, c); + var r = Math.floor(eventToMouseY(event, canvas) / tileSize); + var c = Math.floor(eventToMouseX(event, canvas) / tileSize); + // since the canvas is centered, the bounding client rect can be half-pixel aligned, + // resulting in slightly out-of-bounds mouse events. + r = clamp(r, 0, level.height); + c = clamp(c, 0, level.width); + return getLocation(level, r, c); } function eventToMouseX(event, canvas) { return event.clientX - canvas.getBoundingClientRect().left; } function eventToMouseY(event, canvas) { return event.clientY - canvas.getBoundingClientRect().top; } function selectAll() { - selectionStart = 0; - selectionEnd = level.map.length - 1; - setPaintBrushTileCode("select"); + selectionStart = 0; + selectionEnd = level.map.length - 1; + setPaintBrushTileCode("select"); } function setPaintBrushTileCode(tileCode) { - if (tileCode === "paste") { - // make sure we have something to paste - if (clipboardData == null) return; - } - if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { - // usually this means to fill in the selection - if (tileCode == null) { - // cancel selection - selectionStart = null; - selectionEnd = null; - return; + if (tileCode === "paste") { + // make sure we have something to paste + if (clipboardData == null) return; } - // fill in the selection - fillSelection(tileCode); - selectionStart = null; - selectionEnd = null; - return; - } - if (tileCode === SNAKE) { - if (paintBrushTileCode === SNAKE) { - // next snake color - paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; + if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { + // usually this means to fill in the selection + if (tileCode == null) { + // cancel selection + selectionStart = null; + selectionEnd = null; + return; + } + // fill in the selection + fillSelection(tileCode); + selectionStart = null; + selectionEnd = null; + return; } - } else if (tileCode === BLOCK) { - var blocks = getBlocks(); - if (paintBrushTileCode === BLOCK && blocks.length > 0) { - // cycle through block ids - blocks.sort(compareId); - if (paintBrushBlockId != null) { - (function() { - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id === paintBrushBlockId) { - i += 1; - if (i < blocks.length) { - // next block id - paintBrushBlockId = blocks[i].id; - } else { - // new block id - paintBrushBlockId = null; - } - return; + if (tileCode === SNAKE) { + if (paintBrushTileCode === SNAKE) { + // next snake color + paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; + } + } else if (tileCode === BLOCK) { + var blocks = getBlocks(); + if (paintBrushTileCode === BLOCK && blocks.length > 0) { + // cycle through block ids + blocks.sort(compareId); + if (paintBrushBlockId != null) { + (function () { + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].id === paintBrushBlockId) { + i += 1; + if (i < blocks.length) { + // next block id + paintBrushBlockId = blocks[i].id; + } else { + // new block id + paintBrushBlockId = null; + } + return; + } + } + throw unreachable() + })(); + } else { + // first one + paintBrushBlockId = blocks[0].id; } - } - throw unreachable() - })(); - } else { - // first one - paintBrushBlockId = blocks[0].id; - } - } else { - // new block id - paintBrushBlockId = null; - } - } else if (tileCode == null) { - // escape - if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { - // stop editing this block, but keep the block brush selected - tileCode = BLOCK; - paintBrushBlockId = null; + } else { + // new block id + paintBrushBlockId = null; + } + } else if (tileCode == null) { + // escape + if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { + // stop editing this block, but keep the block brush selected + tileCode = BLOCK; + paintBrushBlockId = null; + } } - } - paintBrushTileCode = tileCode; - paintBrushTileCodeChanged(); + paintBrushTileCode = tileCode; + paintBrushTileCodeChanged(); } function paintBrushTileCodeChanged() { - paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - var backgroundStyle = ""; - var textColor = ""; - if (tileCode === paintBrushTileCode) { - if (tileCode === SNAKE) { - // show the color of the active snake in the color of the button - backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; - } else { - backgroundStyle = "linear-gradient(#4b91ff, #055ce4)"; - textColor = "white"; - } - } - document.getElementById(id).style.background = backgroundStyle; - document.getElementById(id).style.color = textColor; - }); + paintButtonIdAndTileCodes.forEach(function (pair) { + var id = pair[0]; + var tileCode = pair[1]; + var backgroundStyle = ""; + var textColor = ""; + if (tileCode === paintBrushTileCode) { + if (tileCode === SNAKE) { + // show the color of the active snake in the color of the button + backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; + } else { + backgroundStyle = "linear-gradient(#4b91ff, #055ce4)"; + textColor = "white"; + } + } + document.getElementById(id).style.background = backgroundStyle; + document.getElementById(id).style.color = textColor; + }); - var isSelectionMode = paintBrushTileCode === "select"; - ["cutButton", "copyButton"].forEach(function (id) { - document.getElementById(id).disabled = !isSelectionMode; - }); - document.getElementById("pasteButton").disabled = clipboardData == null; + var isSelectionMode = paintBrushTileCode === "select"; + ["cutButton", "copyButton"].forEach(function (id) { + document.getElementById(id).disabled = !isSelectionMode; + }); + document.getElementById("pasteButton").disabled = clipboardData == null; - render(); + render(); } function cutSelection() { - copySelection(); - fillSelection(SPACE); - render(); + copySelection(); + fillSelection(SPACE); + render(); } function copySelection() { - var selectedLocations = getSelectedLocations(); - if (selectedLocations.length === 0) return; - var selectedObjects = []; - selectedLocations.forEach(function(location) { - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(selectedObjects, object); - }); - setClipboardData({ - level: JSON.parse(JSON.stringify(level)), - selectedLocations: selectedLocations, - selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), - }); + var selectedLocations = getSelectedLocations(); + if (selectedLocations.length === 0) return; + var selectedObjects = []; + selectedLocations.forEach(function (location) { + var object = findObjectAtLocation(location); + if (object != null) addIfNotPresent(selectedObjects, object); + }); + setClipboardData({ + level: JSON.parse(JSON.stringify(level)), + selectedLocations: selectedLocations, + selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), + }); } function setClipboardData(data) { - // find the center - var minR = Infinity; - var maxR = -Infinity; - var minC = Infinity; - var maxC = -Infinity; - data.selectedLocations.forEach(function(location) { - var rowcol = getRowcol(data.level, location); - if (rowcol.r < minR) minR = rowcol.r; - if (rowcol.r > maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var offsetR = Math.floor((minR + maxR) / 2); - var offsetC = Math.floor((minC + maxC) / 2); - - clipboardData = data; - clipboardOffsetRowcol = {r:offsetR, c:offsetC}; - paintBrushTileCodeChanged(); + // find the center + var minR = Infinity; + var maxR = -Infinity; + var minC = Infinity; + var maxC = -Infinity; + data.selectedLocations.forEach(function (location) { + var rowcol = getRowcol(data.level, location); + if (rowcol.r < minR) minR = rowcol.r; + if (rowcol.r > maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var offsetR = Math.floor((minR + maxR) / 2); + var offsetC = Math.floor((minC + maxC) / 2); + + clipboardData = data; + clipboardOffsetRowcol = { r: offsetR, c: offsetC }; + paintBrushTileCodeChanged(); } function fillSelection(tileCode) { - var changeLog = []; - var locations = getSelectedLocations(); - locations.forEach(function(location) { - if (level.map[location] !== tileCode) { - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; - } - removeAnyObjectAtLocation(location, changeLog); - }); - pushUndo(uneditStuff, changeLog); + var changeLog = []; + var locations = getSelectedLocations(); + locations.forEach(function (location) { + if (level.map[location] !== tileCode) { + changeLog.push(["m", location, level.map[location], tileCode]); + level.map[location] = tileCode; + } + removeAnyObjectAtLocation(location, changeLog); + }); + pushUndo(uneditStuff, changeLog); } function getSelectedLocations() { - if (selectionStart == null || selectionEnd == null) return []; - var rowcol1 = getRowcol(level, selectionStart); - var rowcol2 = getRowcol(level, selectionEnd); - var r1 = rowcol1.r; - var c1 = rowcol1.c; - var r2 = rowcol2.r; - var c2 = rowcol2.c; - if (r2 < r1) { - var tmp = r1; - r1 = r2; - r2 = tmp; - } - if (c2 < c1) { - var tmp = c1; - c1 = c2; - c2 = tmp; - } - var objects = []; - var locations = []; - for (var r = r1; r <= r2; r++) { - for (var c = c1; c <= c2; c++) { - var location = getLocation(level, r, c); - locations.push(location); - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(objects, object); + if (selectionStart == null || selectionEnd == null) return []; + var rowcol1 = getRowcol(level, selectionStart); + var rowcol2 = getRowcol(level, selectionEnd); + var r1 = rowcol1.r; + var c1 = rowcol1.c; + var r2 = rowcol2.r; + var c2 = rowcol2.c; + if (r2 < r1) { + var tmp = r1; + r1 = r2; + r2 = tmp; + } + if (c2 < c1) { + var tmp = c1; + c1 = c2; + c2 = tmp; + } + var objects = []; + var locations = []; + for (var r = r1; r <= r2; r++) { + for (var c = c1; c <= c2; c++) { + var location = getLocation(level, r, c); + locations.push(location); + var object = findObjectAtLocation(location); + if (object != null) addIfNotPresent(objects, object); + } } - } - // select the rest of any partially-selected objects - objects.forEach(function(object) { - object.locations.forEach(function(location) { - addIfNotPresent(locations, location); + // select the rest of any partially-selected objects + objects.forEach(function (object) { + object.locations.forEach(function (location) { + addIfNotPresent(locations, location); + }); }); - }); - return locations; + return locations; } function setHeight(newHeight, changeLog) { - if (newHeight < level.height) { - // crop - for (var r = newHeight; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - // also delete non-space tiles - paintTileAtLocation(location, SPACE, changeLog); - } - } - level.map.splice(newHeight * level.width); - } else { - // expand - for (var r = level.height; r < newHeight; r++) { - for (var c = 0; c < level.width; c++) { - level.map.push(SPACE); - } + if (newHeight < level.height) { + // crop + for (var r = newHeight; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + removeAnyObjectAtLocation(location, changeLog); + // also delete non-space tiles + paintTileAtLocation(location, SPACE, changeLog); + } + } + level.map.splice(newHeight * level.width); + } else { + // expand + for (var r = level.height; r < newHeight; r++) { + for (var c = 0; c < level.width; c++) { + level.map.push(SPACE); + } + } } - } - changeLog.push(["h", level.height, newHeight]); - level.height = newHeight; + changeLog.push(["h", level.height, newHeight]); + level.height = newHeight; } function setWidth(newWidth, changeLog) { - if (newWidth < level.width) { - // crop - for (var r = level.height - 1; r >= 0; r--) { - for (var c = level.width - 1; c >= newWidth; c--) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, SPACE, changeLog); - level.map.splice(location, 1); - } - } - } else { - // expand - for (var r = level.height - 1; r >= 0; r--) { - var insertionPoint = level.width * (r + 1); - for (var c = level.width; c < newWidth; c++) { - // boy is this inefficient. ... YOLO! - level.map.splice(insertionPoint, 0, SPACE); - } + if (newWidth < level.width) { + // crop + for (var r = level.height - 1; r >= 0; r--) { + for (var c = level.width - 1; c >= newWidth; c--) { + var location = getLocation(level, r, c); + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, SPACE, changeLog); + level.map.splice(location, 1); + } + } + } else { + // expand + for (var r = level.height - 1; r >= 0; r--) { + var insertionPoint = level.width * (r + 1); + for (var c = level.width; c < newWidth; c++) { + // boy is this inefficient. ... YOLO! + level.map.splice(insertionPoint, 0, SPACE); + } + } } - } - var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); - level.objects.forEach(function(object) { - object.locations = object.locations.map(transformLocation); - }); + var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); + level.objects.forEach(function (object) { + object.locations = object.locations.map(transformLocation); + }); - changeLog.push(["w", level.width, newWidth]); - level.width = newWidth; + changeLog.push(["w", level.width, newWidth]); + level.width = newWidth; } function newSnake(color, location) { - var snakes = findSnakesOfColor(color); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id !== i * snakeColors.length + color) break; - } - return { - type: SNAKE, - id: i * snakeColors.length + color, - dead: false, - locations: [location], - }; + var snakes = findSnakesOfColor(color); + snakes.sort(compareId); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id !== i * snakeColors.length + color) break; + } + return { + type: SNAKE, + id: i * snakeColors.length + color, + dead: false, + locations: [location], + }; } function newBlock(location) { - var blocks = getBlocks(); - blocks.sort(compareId); - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id !== i) break; - } - return { - type: BLOCK, - id: i, - dead: false, // unused - locations: [location], - }; + var blocks = getBlocks(); + blocks.sort(compareId); + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].id !== i) break; + } + return { + type: BLOCK, + id: i, + dead: false, // unused + locations: [location], + }; } function newFruit(location) { - var fruits = getObjectsOfType(FRUIT); - fruits.sort(compareId); - for (var i = 0; i < fruits.length; i++) { - if (fruits[i].id !== i) break; - } - return { - type: FRUIT, - id: i, - dead: false, // unused - locations: [location], - }; + var fruits = getObjectsOfType(FRUIT); + fruits.sort(compareId); + for (var i = 0; i < fruits.length; i++) { + if (fruits[i].id !== i) break; + } + return { + type: FRUIT, + id: i, + dead: false, // unused + locations: [location], + }; } function newPoisonFruit(location) { - var fruits = getObjectsOfType(POISON_FRUIT); - fruits.sort(compareId); - for (var i = 0; i < fruits.length; i++) { - if (fruits[i].id !== i) break; - } - return { - type: POISON_FRUIT, - id: i, - dead: false, // unused - locations: [location], - }; + var fruits = getObjectsOfType(POISON_FRUIT); + fruits.sort(compareId); + for (var i = 0; i < fruits.length; i++) { + if (fruits[i].id !== i) break; + } + return { + type: POISON_FRUIT, + id: i, + dead: false, // unused + locations: [location], + }; } function paintAtLocation(location, changeLog) { - if (typeof paintBrushTileCode === "number") { - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, paintBrushTileCode, changeLog); - } else if (paintBrushTileCode === "resize") { - var toRowcol = getRowcol(level, location); - var dr = toRowcol.r - resizeDragAnchorRowcol.r; - var dc = toRowcol.c - resizeDragAnchorRowcol.c; - resizeDragAnchorRowcol = toRowcol; - if (dr !== 0) setHeight(level.height + dr, changeLog); - if (dc !== 0) setWidth(level.width + dc, changeLog); - } else if (paintBrushTileCode === "select") { - selectionEnd = location; - } else if (paintBrushTileCode === "paste") { - var hoverRowcol = getRowcol(level, location); - var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); - pastedData.selectedLocations.forEach(function(location) { - var tileCode = pastedData.level.map[location]; - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, tileCode, changeLog); - }); - pastedData.selectedObjects.forEach(function(object) { - // refresh the ids so there are no collisions. - if (object.type === SNAKE) { - object.id = newSnake(object.id % snakeColors.length).id; - } else if (object.type === BLOCK) { - object.id = newBlock().id; - } else if (object.type === FRUIT) { - object.id = newFruit().id; - } else if (object.type === POISON_FRUIT) { - object.id = newPoisonFruit().id; - } else throw unreachable(); - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - }); - } else if (paintBrushTileCode === SNAKE) { - var oldSnakeSerialization = serializeObjectState(paintBrushObject); - if (paintBrushObject != null) { - // keep dragging - if (paintBrushObject.locations[0] === location) return; // we just did that - // watch out for self-intersection - var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); - if (selfIntersectionIndex !== -1) { - // truncate from here back - paintBrushObject.locations.splice(selfIntersectionIndex); - } - } + if (typeof paintBrushTileCode === "number") { + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, paintBrushTileCode, changeLog); + } else if (paintBrushTileCode === "resize") { + var toRowcol = getRowcol(level, location); + var dr = toRowcol.r - resizeDragAnchorRowcol.r; + var dc = toRowcol.c - resizeDragAnchorRowcol.c; + resizeDragAnchorRowcol = toRowcol; + if (dr !== 0) setHeight(level.height + dr, changeLog); + if (dc !== 0) setWidth(level.width + dc, changeLog); + } else if (paintBrushTileCode === "select") { + selectionEnd = location; + } else if (paintBrushTileCode === "paste") { + var hoverRowcol = getRowcol(level, location); + var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); + pastedData.selectedLocations.forEach(function (location) { + var tileCode = pastedData.level.map[location]; + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, tileCode, changeLog); + }); + pastedData.selectedObjects.forEach(function (object) { + // refresh the ids so there are no collisions. + if (object.type === SNAKE) { + object.id = newSnake(object.id % snakeColors.length).id; + } else if (object.type === BLOCK) { + object.id = newBlock().id; + } else if (object.type === FRUIT) { + object.id = newFruit().id; + } else if (object.type === POISON_FRUIT) { + object.id = newPoisonFruit().id; + } else throw unreachable(); + level.objects.push(object); + changeLog.push([object.type, object.id, [0, []], serializeObjectState(object)]); + }); + } else if (paintBrushTileCode === SNAKE) { + var oldSnakeSerialization = serializeObjectState(paintBrushObject); + if (paintBrushObject != null) { + // keep dragging + if (paintBrushObject.locations[0] === location) return; // we just did that + // watch out for self-intersection + var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); + if (selfIntersectionIndex !== -1) { + // truncate from here back + paintBrushObject.locations.splice(selfIntersectionIndex); + } + } - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - if (paintBrushObject == null) { - var thereWereNoSnakes = countSnakes() === 0; - paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); - level.objects.push(paintBrushObject); - if (thereWereNoSnakes) activateAnySnakePlease(); - } else { - // extend le snake - paintBrushObject.locations.unshift(location); - } - changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); - } else if (paintBrushTileCode === BLOCK) { - var objectHere = findObjectAtLocation(location); - if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { - // just start editing this block - paintBrushBlockId = objectHere.id; - } else { - // make a change - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - var thisBlock = null; - if (paintBrushBlockId != null) { - thisBlock = findBlockById(paintBrushBlockId); - } - var oldBlockSerialization = serializeObjectState(thisBlock); - if (thisBlock == null) { - // create new block + // make sure there's space behind us + paintTileAtLocation(location, SPACE, changeLog); removeAnyObjectAtLocation(location, changeLog); - thisBlock = newBlock(location); - level.objects.push(thisBlock); - paintBrushBlockId = thisBlock.id; - } else { - var existingIndex = thisBlock.locations.indexOf(location); - if (existingIndex !== -1) { - // reclicking part of this object means to delete just part of it. - if (thisBlock.locations.length === 1) { - // goodbye - removeObject(thisBlock, changeLog); - paintBrushBlockId = null; - } else { - thisBlock.locations.splice(existingIndex, 1); - } + if (paintBrushObject == null) { + var thereWereNoSnakes = countSnakes() === 0; + paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); + level.objects.push(paintBrushObject); + if (thereWereNoSnakes) activateAnySnakePlease(); } else { - // add a tile to the block - removeAnyObjectAtLocation(location, changeLog); - thisBlock.locations.push(location); + // extend le snake + paintBrushObject.locations.unshift(location); } - } - changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); - delete blockSupportRenderCache[thisBlock.id]; - } - } else if (paintBrushTileCode === FRUIT || paintBrushTileCode === POISON_FRUIT) { - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - var object = paintBrushTileCode == FRUIT ? newFruit(location) : newPoisonFruit(location); - level.objects.push(object); - changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); - } else throw unreachable(); - render(); + changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); + } else if (paintBrushTileCode === BLOCK) { + var objectHere = findObjectAtLocation(location); + if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { + // just start editing this block + paintBrushBlockId = objectHere.id; + } else { + // make a change + // make sure there's space behind us + paintTileAtLocation(location, SPACE, changeLog); + var thisBlock = null; + if (paintBrushBlockId != null) { + thisBlock = findBlockById(paintBrushBlockId); + } + var oldBlockSerialization = serializeObjectState(thisBlock); + if (thisBlock == null) { + // create new block + removeAnyObjectAtLocation(location, changeLog); + thisBlock = newBlock(location); + level.objects.push(thisBlock); + paintBrushBlockId = thisBlock.id; + } else { + var existingIndex = thisBlock.locations.indexOf(location); + if (existingIndex !== -1) { + // reclicking part of this object means to delete just part of it. + if (thisBlock.locations.length === 1) { + // goodbye + removeObject(thisBlock, changeLog); + paintBrushBlockId = null; + } else { + thisBlock.locations.splice(existingIndex, 1); + } + } else { + // add a tile to the block + removeAnyObjectAtLocation(location, changeLog); + thisBlock.locations.push(location); + } + } + changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); + delete blockSupportRenderCache[thisBlock.id]; + } + } else if (paintBrushTileCode === FRUIT || paintBrushTileCode === POISON_FRUIT) { + paintTileAtLocation(location, SPACE, changeLog); + removeAnyObjectAtLocation(location, changeLog); + var object = paintBrushTileCode == FRUIT ? newFruit(location) : newPoisonFruit(location); + level.objects.push(object); + changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); + } else throw unreachable(); + render(); } function paintTileAtLocation(location, tileCode, changeLog) { - if (level.map[location] === tileCode) return; - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; + if (level.map[location] === tileCode) return; + changeLog.push(["m", location, level.map[location], tileCode]); + level.map[location] = tileCode; } function pushUndo(undoStuff, changeLog) { - // changeLog = [ - // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], - // // player input for snake 0, dr:-1, dc:0. has no effect on state. - // // "i" is always the first change in normal player movement. - // // if a changeLog does not start with "i", then it is an editor action. - // // animationQueue and freshlyRemovedAnimatedObjects - // // are used for animating re-move. - // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 - // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] - // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] - // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] - // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] - // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. - // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. - // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. - // 10, // the last change is always a declaration of the final width of the map. - // ]; - reduceChangeLog(changeLog); - if (changeLog.length === 0) return; - changeLog.push(level.width); - undoStuff.undoStack.push(changeLog); - undoStuff.redoStack = []; - paradoxes = []; - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; - - undoStuffChanged(undoStuff); + // changeLog = [ + // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], + // // player input for snake 0, dr:-1, dc:0. has no effect on state. + // // "i" is always the first change in normal player movement. + // // if a changeLog does not start with "i", then it is an editor action. + // // animationQueue and freshlyRemovedAnimatedObjects + // // are used for animating re-move. + // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 + // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] + // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] + // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] + // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] + // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. + // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. + // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. + // 10, // the last change is always a declaration of the final width of the map. + // ]; + reduceChangeLog(changeLog); + if (changeLog.length === 0) return; + changeLog.push(level.width); + undoStuff.undoStack.push(changeLog); + undoStuff.redoStack = []; + paradoxes = []; + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; + + undoStuffChanged(undoStuff); } function reduceChangeLog(changeLog) { - for (var i = 0; i < changeLog.length - 1; i++) { - var change = changeLog[i]; - if (change[0] === "i") { - continue; // don't reduce player input - } else if (change[0] === "h") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "h") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "w") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "w") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "w") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "h") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "m") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "m" && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (change[2] === change[3]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === change[0] && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (deepEquals(change[2], change[3])) { - // no change - changeLog.splice(i, 1); - i--; - } - } else throw unreachable(); - } + for (var i = 0; i < changeLog.length - 1; i++) { + var change = changeLog[i]; + if (change[0] === "i") { + continue; // don't reduce player input + } else if (change[0] === "h") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "h") { + // combine + change[2] = otherChange[2]; + changeLog.splice(j, 1); + j--; + continue; + } else if (otherChange[0] === "w") { + continue; // no interaction between height and width + } else break; // no more reduction possible + } + if (change[1] === change[2]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === "w") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "w") { + // combine + change[2] = otherChange[2]; + changeLog.splice(j, 1); + j--; + continue; + } else if (otherChange[0] === "h") { + continue; // no interaction between height and width + } else break; // no more reduction possible + } + if (change[1] === change[2]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === "m") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "m" && otherChange[1] === change[1]) { + // combine + change[3] = otherChange[3]; + changeLog.splice(j, 1); + j--; + } else if (otherChange[0] === "w" || otherChange[0] === "h") { + break; // can't reduce accros resizes + } + } + if (change[2] === change[3]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === change[0] && otherChange[1] === change[1]) { + // combine + change[3] = otherChange[3]; + changeLog.splice(j, 1); + j--; + } else if (otherChange[0] === "w" || otherChange[0] === "h") { + break; // can't reduce accros resizes + } + } + if (deepEquals(change[2], change[3])) { + // no change + changeLog.splice(i, 1); + i--; + } + } else throw unreachable(); + } } function undo(undoStuff) { - if (undoStuff.undoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - undoOneFrame(undoStuff); - undoStuffChanged(undoStuff); + if (undoStuff.undoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + undoOneFrame(undoStuff); + undoStuffChanged(undoStuff); } function reset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.undoStack.length > 0) { - undoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + while (undoStuff.undoStack.length > 0) { + undoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); } function undoOneFrame(undoStuff) { - var doThis = undoStuff.undoStack.pop(); - var redoChangeLog = []; - undoChanges(doThis, redoChangeLog); - if (redoChangeLog.length > 0) { - redoChangeLog.push(level.width); - undoStuff.redoStack.push(redoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; + var doThis = undoStuff.undoStack.pop(); + var redoChangeLog = []; + undoChanges(doThis, redoChangeLog); + if (redoChangeLog.length > 0) { + redoChangeLog.push(level.width); + undoStuff.redoStack.push(redoChangeLog); + } + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; } function redo(undoStuff) { - if (undoStuff.redoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - redoOneFrame(undoStuff); - undoStuffChanged(undoStuff); + if (undoStuff.redoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + redoOneFrame(undoStuff); + undoStuffChanged(undoStuff); } function redoAll(undoStuff) { - if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); - // preserve the level in the url bar. - var hash = "#level=" + currentSerializedLevel; - if (dirtyState === REPLAY_DIRTY) { - // there is a replay to save - hash += "#replay=" + compressSerialization(stringifyReplay()); - } - - var sv = "https://jmdiamond3.github.io/Snakefall-Redesign/SolutionVerification.html" + hash; - copyToClipboard(sv); + if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); + // preserve the level in the url bar. + var hash = "#level=" + currentSerializedLevel; + if (dirtyState === REPLAY_DIRTY) { + // there is a replay to save + hash += "#replay=" + compressSerialization(stringifyReplay()); + } + + var sv = "https://jmdiamond3.github.io/Snakefall-Redesign/SolutionVerification.html" + hash; + copyToClipboard(sv); } function copyToClipboard(text) { var dummy = document.createElement("textarea"); @@ -1462,199 +1462,199 @@ function copyToClipboard(text) { document.body.removeChild(dummy); } function unreset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.redoStack.length > 0) { - redoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + while (undoStuff.redoStack.length > 0) { + redoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); - // don't animate the last frame - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; + // don't animate the last frame + animationQueue = []; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = []; } function redoOneFrame(undoStuff) { - var doThis = undoStuff.redoStack.pop(); - var undoChangeLog = []; - undoChanges(doThis, undoChangeLog); - if (undoChangeLog.length > 0) { - undoChangeLog.push(level.width); - undoStuff.undoStack.push(undoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; + var doThis = undoStuff.redoStack.pop(); + var undoChangeLog = []; + undoChanges(doThis, undoChangeLog); + if (undoChangeLog.length > 0) { + undoChangeLog.push(level.width); + undoStuff.undoStack.push(undoChangeLog); + } + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; } function undoChanges(changes, changeLog) { - var widthContext = changes.pop(); - var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); - for (var i = changes.length - 1; i >= 0; i--) { - var paradoxDescription = undoChange(changes[i]); - if (paradoxDescription != null) paradoxes.push(paradoxDescription); - } - - var lastChange = changes[changes.length - 1]; - if (lastChange[0] === "i") { - // replay animation - animationQueue = lastChange[4]; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = lastChange[5]; - animationStart = new Date().getTime(); - } - - function undoChange(change) { - // note: everything here is going backwards: to -> from - if (change[0] === "i") { - // no state change, but preserve the intention. - changeLog.push(change); - return null; - } else if (change[0] === "h") { - // change height - var fromHeight = change[1]; - var toHeight = change[2]; - if (level.height !== toHeight) return "Impossible"; - setHeight(fromHeight, changeLog); - } else if (change[0] === "w") { - // change width - var fromWidth = change[1]; - var toWidth = change[2]; - if (level.width !== toWidth) return "Impossible"; - setWidth(fromWidth, changeLog); - } else if (change[0] === "m") { - // change map tile - var location = transformLocation(change[1]); - var fromTileCode = change[2]; - var toTileCode = change[3]; - if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; - if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; - paintTileAtLocation(location, fromTileCode, changeLog); - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { - // change object - var type = change[0]; - var id = change[1]; - var fromDead = change[2][0]; - var toDead = change[3][0]; - var fromLocations = change[2][1].map(transformLocation); - var toLocations = change[3][1].map(transformLocation); - if (fromLocations.filter(function(location) { return location >= level.map.length; }).length > 0) { - return "Can't move " + describe(type, id) + " out of bounds"; - } - var object = findObjectOfTypeAndId(type, id); - if (toLocations.length !== 0) { - // should exist at this location - if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; - if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; - if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; - // doit - if (fromLocations.length !== 0) { - var oldState = serializeObjectState(object); - object.locations = fromLocations; - object.dead = fromDead; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - } else { - removeObject(object, changeLog); - } - } else { - // shouldn't exist - if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; - // doit - object = { - type: type, - id: id, - dead: fromDead, - locations: fromLocations, - }; - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - } - } else throw unreachable(); - } + var widthContext = changes.pop(); + var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); + for (var i = changes.length - 1; i >= 0; i--) { + var paradoxDescription = undoChange(changes[i]); + if (paradoxDescription != null) paradoxes.push(paradoxDescription); + } + + var lastChange = changes[changes.length - 1]; + if (lastChange[0] === "i") { + // replay animation + animationQueue = lastChange[4]; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = lastChange[5]; + animationStart = new Date().getTime(); + } + + function undoChange(change) { + // note: everything here is going backwards: to -> from + if (change[0] === "i") { + // no state change, but preserve the intention. + changeLog.push(change); + return null; + } else if (change[0] === "h") { + // change height + var fromHeight = change[1]; + var toHeight = change[2]; + if (level.height !== toHeight) return "Impossible"; + setHeight(fromHeight, changeLog); + } else if (change[0] === "w") { + // change width + var fromWidth = change[1]; + var toWidth = change[2]; + if (level.width !== toWidth) return "Impossible"; + setWidth(fromWidth, changeLog); + } else if (change[0] === "m") { + // change map tile + var location = transformLocation(change[1]); + var fromTileCode = change[2]; + var toTileCode = change[3]; + if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; + if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; + paintTileAtLocation(location, fromTileCode, changeLog); + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT || change[0] === POISON_FRUIT) { + // change object + var type = change[0]; + var id = change[1]; + var fromDead = change[2][0]; + var toDead = change[3][0]; + var fromLocations = change[2][1].map(transformLocation); + var toLocations = change[3][1].map(transformLocation); + if (fromLocations.filter(function (location) { return location >= level.map.length; }).length > 0) { + return "Can't move " + describe(type, id) + " out of bounds"; + } + var object = findObjectOfTypeAndId(type, id); + if (toLocations.length !== 0) { + // should exist at this location + if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; + if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; + if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; + // doit + if (fromLocations.length !== 0) { + var oldState = serializeObjectState(object); + object.locations = fromLocations; + object.dead = fromDead; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + } else { + removeObject(object, changeLog); + } + } else { + // shouldn't exist + if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; + // doit + object = { + type: type, + id: id, + dead: fromDead, + locations: fromLocations, + }; + level.objects.push(object); + changeLog.push([object.type, object.id, [0, []], serializeObjectState(object)]); + } + } else throw unreachable(); + } } function describe(arg1, arg2) { - // describe(0) -> "Space" - // describe(SNAKE, 0) -> "Snake 0 (Red)" - // describe(object) -> "Snake 0 (Red)" - // describe(BLOCK, 1) -> "Block 1" - // describe(FRUIT) -> "Fruit" - if (typeof arg1 === "number") { - switch (arg1) { - case SPACE: return "Space"; - case WALL: return "a Wall"; - case SPIKE: return "Spikes"; - case EXIT: return "an Exit"; - case PORTAL: return "a Portal"; - case PLATFORM: return "a Platform"; - case WOODPLATFORM: return "a Wooden Platform"; - case ONEWAYWALLU: return "a One Way Wall (facing U)"; - case ONEWAYWALLD: return "a One Way Wall (facing D)"; - case ONEWAYWALLL: return "a One Way Wall (facing L)"; - case ONEWAYWALLR: return "a One Way Wall (facing R)"; - case CLOSEDLIFT: return "a Closed Lift"; - case OPENLIFT: return "an Open Lift"; - case CLOUD: return "a Cloud"; - case BUBBLE: return "a Bubble"; - case LAVA: return "Lava"; - case WATER: return "Water"; - default: throw unreachable(); + // describe(0) -> "Space" + // describe(SNAKE, 0) -> "Snake 0 (Red)" + // describe(object) -> "Snake 0 (Red)" + // describe(BLOCK, 1) -> "Block 1" + // describe(FRUIT) -> "Fruit" + if (typeof arg1 === "number") { + switch (arg1) { + case SPACE: return "Space"; + case WALL: return "a Wall"; + case SPIKE: return "Spikes"; + case EXIT: return "an Exit"; + case PORTAL: return "a Portal"; + case PLATFORM: return "a Platform"; + case WOODPLATFORM: return "a Wooden Platform"; + case ONEWAYWALLU: return "a One Way Wall (facing U)"; + case ONEWAYWALLD: return "a One Way Wall (facing D)"; + case ONEWAYWALLL: return "a One Way Wall (facing L)"; + case ONEWAYWALLR: return "a One Way Wall (facing R)"; + case CLOSEDLIFT: return "a Closed Lift"; + case OPENLIFT: return "an Open Lift"; + case CLOUD: return "a Cloud"; + case BUBBLE: return "a Bubble"; + case LAVA: return "Lava"; + case WATER: return "Water"; + default: throw unreachable(); + } } - } - if (arg1 === SNAKE) { - var color = (function() { - switch (snakeColors[arg2 % snakeColors.length]) { - case "#fd0c0b": return " (Red)"; - case "#18d11f": return " (Green)"; - case "#004cff": return " (Blue)"; - case "#fdc122": return " (Yellow)"; - default: throw unreachable(); - } - })(); - return "Snake " + arg2 + color; - } - if (arg1 === BLOCK) { - return "Block " + arg2; - } - if (arg1 === FRUIT) { - return "Fruit"; - } - if (arg1 === POISON_FRUIT) { - return "Poison Fruit"; - } - if (typeof arg1 === "object") return describe(arg1.type, arg1.id); - throw unreachable(); + if (arg1 === SNAKE) { + var color = (function () { + switch (snakeColors[arg2 % snakeColors.length]) { + case "#fd0c0b": return " (Red)"; + case "#18d11f": return " (Green)"; + case "#004cff": return " (Blue)"; + case "#fdc122": return " (Yellow)"; + default: throw unreachable(); + } + })(); + return "Snake " + arg2 + color; + } + if (arg1 === BLOCK) { + return "Block " + arg2; + } + if (arg1 === FRUIT) { + return "Fruit"; + } + if (arg1 === POISON_FRUIT) { + return "Poison Fruit"; + } + if (typeof arg1 === "object") return describe(arg1.type, arg1.id); + throw unreachable(); } function undoStuffChanged(undoStuff) { - var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; - document.getElementById(undoStuff.spanId).textContent = movesText; - document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; - document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; - - // render paradox display - var uniqueParadoxes = []; - var paradoxCounts = []; - paradoxes.forEach(function(paradoxDescription) { - var index = uniqueParadoxes.indexOf(paradoxDescription); - if (index !== -1) { - paradoxCounts[index] += 1; - } else { - uniqueParadoxes.push(paradoxDescription); - paradoxCounts.push(1); + var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; + document.getElementById(undoStuff.spanId).textContent = movesText; + document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; + document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; + + // render paradox display + var uniqueParadoxes = []; + var paradoxCounts = []; + paradoxes.forEach(function (paradoxDescription) { + var index = uniqueParadoxes.indexOf(paradoxDescription); + if (index !== -1) { + paradoxCounts[index] += 1; + } else { + uniqueParadoxes.push(paradoxDescription); + paradoxCounts.push(1); + } + }); + var paradoxDivContent = ""; + uniqueParadoxes.forEach(function (paradox, i) { + if (i > 0) paradoxDivContent += "
    \n"; + if (paradoxCounts[i] > 1) paradoxDivContent += "(" + paradoxCounts[i] + "x) "; + paradoxDivContent += "Time Travel Paradox! " + uniqueParadoxes[i]; + }); + document.getElementById("paradoxDiv").innerHTML = paradoxDivContent; + + updateDirtyState(); + + if (unmoveStuff.redoStack.length === 0) { + document.getElementById("removeButton").classList.remove("click-me"); } - }); - var paradoxDivContent = ""; - uniqueParadoxes.forEach(function(paradox, i) { - if (i > 0) paradoxDivContent += "
    \n"; - if (paradoxCounts[i] > 1) paradoxDivContent += "(" + paradoxCounts[i] + "x) "; - paradoxDivContent += "Time Travel Paradox! " + uniqueParadoxes[i]; - }); - document.getElementById("paradoxDiv").innerHTML = paradoxDivContent; - - updateDirtyState(); - - if (unmoveStuff.redoStack.length === 0) { - document.getElementById("removeButton").classList.remove("click-me"); - } } var CLEAN_NO_TIMELINES = 0; @@ -1664,72 +1664,72 @@ var EDITOR_DIRTY = 3; var dirtyState = CLEAN_NO_TIMELINES; var editorHasBeenTouched = false; function updateDirtyState() { - if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { - dirtyState = EDITOR_DIRTY; - } else if (unmoveStuff.undoStack.length > 0) { - dirtyState = REPLAY_DIRTY; - } else if (unmoveStuff.redoStack.length > 0) { - dirtyState = CLEAN_WITH_REDO; - } else { - dirtyState = CLEAN_NO_TIMELINES; - } - - var saveLevelButton = document.getElementById("saveLevelButton"); - // the save button clears your timelines - saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; - if (dirtyState >= EDITOR_DIRTY) { - // you should save - saveLevelButton.classList.add("click-me"); - } else { - saveLevelButton.classList.remove("click-me"); - } - - var saveProgressButton = document.getElementById("saveProgressButton"); - // you can't save a replay if your level is dirty - if (dirtyState === CLEAN_WITH_REDO) { - saveProgressButton.textContent = "Forget Progress"; - } else { - saveProgressButton.textContent = "Save Progress"; - } - saveProgressButton.disabled = dirtyState >= EDITOR_DIRTY || dirtyState === CLEAN_NO_TIMELINES; + if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { + dirtyState = EDITOR_DIRTY; + } else if (unmoveStuff.undoStack.length > 0) { + dirtyState = REPLAY_DIRTY; + } else if (unmoveStuff.redoStack.length > 0) { + dirtyState = CLEAN_WITH_REDO; + } else { + dirtyState = CLEAN_NO_TIMELINES; + } + + var saveLevelButton = document.getElementById("saveLevelButton"); + // the save button clears your timelines + saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; + if (dirtyState >= EDITOR_DIRTY) { + // you should save + saveLevelButton.classList.add("click-me"); + } else { + saveLevelButton.classList.remove("click-me"); + } + + var saveProgressButton = document.getElementById("saveProgressButton"); + // you can't save a replay if your level is dirty + if (dirtyState === CLEAN_WITH_REDO) { + saveProgressButton.textContent = "Forget Progress"; + } else { + saveProgressButton.textContent = "Save Progress"; + } + saveProgressButton.disabled = dirtyState >= EDITOR_DIRTY || dirtyState === CLEAN_NO_TIMELINES; } function haveCheatcodesBeenUsed() { - return !unmoveStuff.undoStack.every(function(changeLog) { - // normal movement always starts with "i". - return changeLog[0][0] === "i"; - }); + return !unmoveStuff.undoStack.every(function (changeLog) { + // normal movement always starts with "i". + return changeLog[0][0] === "i"; + }); } var persistentState = { - showEditor: false, - showGrid: false, + showEditor: false, + showGrid: false, }; function savePersistentState() { - localStorage.snakefall = JSON.stringify(persistentState); + localStorage.snakefall = JSON.stringify(persistentState); } function loadPersistentState() { - try { - persistentState = JSON.parse(localStorage.snakefall); - } catch (e) { - } - persistentState.showEditor = !!persistentState.showEditor; - persistentState.showGrid = !!persistentState.showGrid; - showEditorChanged(); + try { + persistentState = JSON.parse(localStorage.snakefall); + } catch (e) { + } + persistentState.showEditor = !!persistentState.showEditor; + persistentState.showGrid = !!persistentState.showGrid; + showEditorChanged(); } var isGravityEnabled = true; function isGravity() { - return isGravityEnabled || !persistentState.showEditor; + return isGravityEnabled || !persistentState.showEditor; } var isCollisionEnabled = true; function isCollision() { - return isCollisionEnabled || !persistentState.showEditor; + return isCollisionEnabled || !persistentState.showEditor; } function isAnyCheatcodeEnabled() { - return persistentState.showEditor && ( - !isGravityEnabled || !isCollisionEnabled - ); + return persistentState.showEditor && ( + !isGravityEnabled || !isCollisionEnabled + ); } -var themeName = "Spring"; //Gooby +var themeName = "Spring"; var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle, experimentalColors; var curlyOutline = false; @@ -1738,35 +1738,23 @@ var bg2 = "rgba(254, 198, 145 * rgba(255, 192, 133"; var bg3 = "rgba(145, 254, 198 * rgba(117, 255, 192"; var bg4 = "rgba(7, 7, 83 * rgba(0, 0, 70"; -var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; -var snakeColors2 = ["#f00", "#0f0", "#00f", "#ff0"]; +var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; //must be full length to satisfy tint function +var snakeColors2 = ["#ff0000", "#00ff00", "#0000ff", "#ffff00"]; var snakeColors3 = ["#BA145C", "#E91624", "#F75802", "#FEFE28"]; -var fruitColors1 = ["#ff0066","#ff36a6","#ff6b1f","#ff9900","#ff2600"]; -var fruitColors2 = ["black","black","black","black","black"]; +var fruitColors1 = ["#ff0066", "#ff36a6", "#ff6b1f", "#ff9900", "#ff2600"]; +var fruitColors2 = ["black", "black", "black", "black", "black"]; var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spike, support, box, bolt var spikeColors2 = ["gray", "black", "white", "black"]; var spikeColors3 = ["#333", "#333", "#333", "#777"]; -var blockColors1 = [ - ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"], - ["#853641","#963c84","#753d88","#5d3a96","#3a3990"] -]; -var blockColors2 = [ - ["#999"], - ["#999"] -]; -var blockColors3 = [ - ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"], - ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] -]; -var blockColors4 = [ - ["#150612", "#a52e8b", "#990077", "#d917af", "#4d003c"], - ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] -]; +var blockColors1 = ["#de5a6d", "#fa65dd", "#c367e3", "#9c62fa", "#625ff0"]; //must be full length to satisfy tint function +var blockColors2 = ["#999999"]; +var blockColors3 = ["#de7913", "#7d46a0", "#39868b", "#41ccc2", "#ded800"]; +var blockColors4 = ["#150612", "#a52e8b", "#990077", "#d917af", "#4d003c"]; -var fontSize = tileSize*5; +var fontSize = tileSize * 5; var textStyle1 = ["" + fontSize + "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose var textStyle2 = ["" + fontSize + "px Impact", "#5702c6", "#ff0098"]; var textStyle3 = ["" + fontSize + "px Impact", "#BA145C", "#F75802"]; @@ -1778,547 +1766,542 @@ var experimentalColors2 = ["white", "#FEFE28"]; var themeCounter = 0; var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor, textStyle, experimentalColors - //["sky",], - ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], - ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], - ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], - ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] + //["sky",], + ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], + ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], + ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], + ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], + ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], + ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] ]; function showEditorChanged() { - document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; - ["editorDiv", "editorPane"].forEach(function(id) { - document.getElementById(id).style.display = persistentState.showEditor ? "block" : "none"; - }); - document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : "/WASD"; + document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; + ["editorDiv", "editorPane"].forEach(function (id) { + document.getElementById(id).style.display = persistentState.showEditor ? "block" : "none"; + }); + document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : "/WASD"; - render(); + render(); } function move(dr, dc) { - if (!isAlive()) return; - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; - animationStart = new Date().getTime(); - var activeSnake = findActiveSnake(); - var headRowcol = getRowcol(level, activeSnake.locations[0]); - var newRowcol = {r:headRowcol.r + dr, c:headRowcol.c + dc}; - if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; - var newLocation = getLocation(level, newRowcol.r, newRowcol.c); - var changeLog = []; - - // The changeLog for a player movement starts with the input - // when playing normally. - if (!isAnyCheatcodeEnabled()) { - changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); - } - - var ate = false; - var ate_poison = false; - var pushedObjects = []; - - //track ClosedLifts that had objects on them - var occupiedClosedLift = getOccupiedClosedLiftLocations(); - - if (isCollision()) { - var newTile = level.map[newLocation]; - if (newTile === BUBBLE || newTile === CLOUD) - paintTileAtLocation(newLocation, SPACE, changeLog); - else if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile - var otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { - if (otherObject === activeSnake) return; // can't push yourself - if (otherObject.type === FRUIT) { - // eat - removeObject(otherObject, changeLog); - ate = true; - } else if (otherObject.type === POISON_FRUIT) { - // eat poison - removeObject(otherObject, changeLog); - ate_poison = true; - } else if (isTileCodeAir(activeSnake, null, newTile, dr, dc)) { - otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { - if (otherObject === activeSnake) return; // can't push yourself - // push objects - if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; - } - } else return; // can't go through that tile + if (!isAlive()) return; + animationQueue = []; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = []; + animationStart = new Date().getTime(); + var activeSnake = findActiveSnake(); + var headRowcol = getRowcol(level, activeSnake.locations[0]); + var newRowcol = { r: headRowcol.r + dr, c: headRowcol.c + dc }; + if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; + var newLocation = getLocation(level, newRowcol.r, newRowcol.c); + var changeLog = []; + + // The changeLog for a player movement starts with the input + // when playing normally. + if (!isAnyCheatcodeEnabled()) { + changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); } - } - - // slither forward - var activeSnakeOldState = serializeObjectState(activeSnake); - var size1 = activeSnake.locations.length === 1; - var slitherAnimations = [ - 70, - [ - // size-1 snakes really do more of a move than a slither - size1 ? MOVE_SNAKE : SLITHER_HEAD, - activeSnake.id, - dr, - dc, - ] - ]; - activeSnake.locations.unshift(newLocation); - - // drag your tail forward based on what was/wasn't eaten - var times = 1; - if (ate) { times--; } - if (ate_poison) { times++; } - //if we're going to shrink out of existence, prevent it - var snake_length = activeSnake.locations.length-1; - if (times > snake_length) - { - times = snake_length; - activeSnake.dead = true; - //make the snake appear to vanish into non-existence - activeSnake.locations[0] = {r:-99, c:-99}; - } - for (var t = 0; t < times; ++t) { - for(var i = 1; i snake_length) { + times = snake_length; + activeSnake.dead = true; + //make the snake appear to vanish into non-existence + activeSnake.locations[0] = { r: -99, c: -99 }; + } + for (var t = 0; t < times; ++t) { + for (var i = 1; i < activeSnake.locations.length; i++) { + // drag your tail forward + var oldRowcol = getRowcol(level, activeSnake.locations[i + 1]); + newRowcol = getRowcol(level, activeSnake.locations[i]); + if (!size1) { + slitherAnimations.push([ + SLITHER_TAIL, + activeSnake.id, + newRowcol.r - oldRowcol.r, + newRowcol.c - oldRowcol.c, + ]); + } } - } + activeSnake.locations.pop(); } - - occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); + changeLog.push([activeSnake.type, activeSnake.id, activeSnakeOldState, serializeObjectState(activeSnake)]); - // fall - var dyingObjects = []; - var fallingObjects = level.objects.filter(function(object) { - if (object.type === FRUIT || object.type === POISON_FRUIT) return; // can't fall - var theseDyingObjects = []; - if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; - // this object can fall. maybe more will fall with it too. we'll check those separately. - theseDyingObjects.forEach(function(object) { - addIfNotPresent(dyingObjects, object); - }); - return true; - }); - if (dyingObjects.length > 0) { - var anySnakesDied = false; - dyingObjects.forEach(function(object) { - if (object.type === SNAKE) { - // look what you've done - var oldState = serializeObjectState(object); - object.dead = true; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - anySnakesDied = true; - } else if (object.type === BLOCK) { - // a box fell off the world - removeAnimatedObject(object, changeLog); - removeFromArray(fallingObjects, object); - exitAnimationQueue.push([ - 200, - [ - DIE_BLOCK, - object.id, - 0, 0 - ], - ]); - didAnything = true; - } else throw unreachable(); - }); - if (anySnakesDied) break; + // did you just push your face into a portal? + var portalLocations = getActivePortalLocations(); + var portalActivationLocations = []; + if (portalLocations.indexOf(newLocation) !== -1) { + portalActivationLocations.push(newLocation); } - if (fallingObjects.length > 0) { - moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); - didAnything = true; - } - - occupiedClosedLift = openLift(occupiedClosedLift, changeLog); + // push everything, too + moveObjects(pushedObjects, dr, dc, portalLocations, portalActivationLocations, changeLog, slitherAnimations); + animationQueue.push(slitherAnimations); - if (!didAnything) break; - Array.prototype.push.apply(animationQueue, exitAnimationQueue); - if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); - } + occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); - pushUndo(unmoveStuff, changeLog); - render(); + // gravity loop + var stateToAnimationIndex = {}; + if (isGravity()) for (var fallHeight = 1; ; fallHeight++) { + var serializedState = serializeObjects(level.objects); + var infiniteLoopStartIndex = stateToAnimationIndex[serializedState]; + if (infiniteLoopStartIndex != null) { + // infinite loop + animationQueue.push([0, [INFINITE_LOOP, animationQueue.length - infiniteLoopStartIndex]]); + break; + } else { + stateToAnimationIndex[serializedState] = animationQueue.length; + } + // do portals separate from falling logic + if (portalActivationLocations.length === 1) { + var portalAnimations = [500]; + if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { + animationQueue.push(portalAnimations); + } + portalActivationLocations = []; + } + // now do falling logic + var didAnything = false; + var fallingAnimations = [ + 70 / Math.sqrt(fallHeight), + ]; + var exitAnimationQueue = []; + + // check for exit + if (!isUneatenFruit()) { + var snakes = getSnakes(); + for (var i = 0; i < snakes.length; i++) { + var snake = snakes[i]; + if (level.map[snake.locations[0]] === EXIT) { + // (one of) you made it! + removeAnimatedObject(snake, changeLog); + exitAnimationQueue.push([ + 200, + [EXIT_SNAKE, snake.id, 0, 0], + ]); + didAnything = true; + } + } + } + + occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); + + // fall + var dyingObjects = []; + var fallingObjects = level.objects.filter(function (object) { + if (object.type === FRUIT || object.type === POISON_FRUIT) return; // can't fall + var theseDyingObjects = []; + if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; + // this object can fall. maybe more will fall with it too. we'll check those separately. + theseDyingObjects.forEach(function (object) { + addIfNotPresent(dyingObjects, object); + }); + return true; + }); + if (dyingObjects.length > 0) { + var anySnakesDied = false; + dyingObjects.forEach(function (object) { + if (object.type === SNAKE) { + // look what you've done + var oldState = serializeObjectState(object); + object.dead = true; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + anySnakesDied = true; + } else if (object.type === BLOCK) { + // a box fell off the world + removeAnimatedObject(object, changeLog); + removeFromArray(fallingObjects, object); + exitAnimationQueue.push([ + 200, + [ + DIE_BLOCK, + object.id, + 0, 0 + ], + ]); + didAnything = true; + } else throw unreachable(); + }); + if (anySnakesDied) break; + } + if (fallingObjects.length > 0) { + moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); + didAnything = true; + } + + occupiedClosedLift = openLift(occupiedClosedLift, changeLog); + + if (!didAnything) break; + Array.prototype.push.apply(animationQueue, exitAnimationQueue); + if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); + } + + pushUndo(unmoveStuff, changeLog); + render(); } -function combineOldAndNewLiftOccupations(oldOccupiedClosedLift) -{ - var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); - var newlyOccupiedClosedLift = getSetSubtract(newOccupiedClosedLift, oldOccupiedClosedLift); - return oldOccupiedClosedLift.concat(newlyOccupiedClosedLift); +function combineOldAndNewLiftOccupations(oldOccupiedClosedLift) { + var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); + var newlyOccupiedClosedLift = getSetSubtract(newOccupiedClosedLift, oldOccupiedClosedLift); + return oldOccupiedClosedLift.concat(newlyOccupiedClosedLift); } -function openLift(oldOccupiedClosedLift, changeLog) -{ - var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); - var nowUnoccupiedClosedLift = getSetSubtract(oldOccupiedClosedLift, newOccupiedClosedLift); - for (var i = 0; i < nowUnoccupiedClosedLift.length; i++) { - paintTileAtLocation(nowUnoccupiedClosedLift[i], OPENLIFT, changeLog); - } - return newOccupiedClosedLift; +function openLift(oldOccupiedClosedLift, changeLog) { + var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); + var nowUnoccupiedClosedLift = getSetSubtract(oldOccupiedClosedLift, newOccupiedClosedLift); + for (var i = 0; i < nowUnoccupiedClosedLift.length; i++) { + paintTileAtLocation(nowUnoccupiedClosedLift[i], OPENLIFT, changeLog); + } + return newOccupiedClosedLift; } function getSetSubtract(array1, array2) { - if (array1.length === 0) return []; - return array1.filter(function(x) { return array2.indexOf(x) == -1; }); + if (array1.length === 0) return []; + return array1.filter(function (x) { return array2.indexOf(x) == -1; }); } function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects) { - // pusher can be null (for gravity) - pushedObjects.push(pushedObject); - // find forward locations - var forwardLocations = []; - for (var i = 0; i < pushedObjects.length; i++) { - pushedObject = pushedObjects[i]; - for (var j = 0; j < pushedObject.locations.length; j++) { - var rowcol = getRowcol(level, pushedObject.locations[j]); - var forwardRowcol = {r:rowcol.r + dr, c:rowcol.c + dc}; - if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { - if (dyingObjects == null) { - // can't push things out of bounds - return false; - } else { - // this thing is going to fall out of bounds - addIfNotPresent(dyingObjects, pushedObject); - addIfNotPresent(pushedObjects, pushedObject); - continue; - } - } - var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); - if (dr === 1 && level.map[forwardLocation] === PLATFORM) { - // this platform holds us, unless we're going through it - var neighborLocations; - if (pushedObject.type === SNAKE) { - neighborLocations = []; - if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); - if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); - } else if (pushedObject.type === BLOCK) { - neighborLocations = pushedObject.locations; - } else throw asdf; - if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface - // we slip right past it - } - var yetAnotherObject = findObjectAtLocation(forwardLocation); - if (yetAnotherObject != null) { - if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === POISON_FRUIT) { - // not pushable - return false; - } - if (yetAnotherObject === pusher) { - // indirect pushing ourselves. - // special check for when we're indirectly pushing the tip of our own tail. - if (forwardLocation === pusher.locations[pusher.locations.length -1]) { - // for some reason this is ok. ------------ THIS IS THE TAIL GLITCH - continue; - } - return false; + // pusher can be null (for gravity) + pushedObjects.push(pushedObject); + // find forward locations + var forwardLocations = []; + for (var i = 0; i < pushedObjects.length; i++) { + pushedObject = pushedObjects[i]; + for (var j = 0; j < pushedObject.locations.length; j++) { + var rowcol = getRowcol(level, pushedObject.locations[j]); + var forwardRowcol = { r: rowcol.r + dr, c: rowcol.c + dc }; + if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { + if (dyingObjects == null) { + // can't push things out of bounds + return false; + } else { + // this thing is going to fall out of bounds + addIfNotPresent(dyingObjects, pushedObject); + addIfNotPresent(pushedObjects, pushedObject); + continue; + } + } + var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); + if (dr === 1 && level.map[forwardLocation] === PLATFORM) { + // this platform holds us, unless we're going through it + var neighborLocations; + if (pushedObject.type === SNAKE) { + neighborLocations = []; + if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); + if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); + } else if (pushedObject.type === BLOCK) { + neighborLocations = pushedObject.locations; + } else throw asdf; + if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface + // we slip right past it + } + var yetAnotherObject = findObjectAtLocation(forwardLocation); + if (yetAnotherObject != null) { + if (yetAnotherObject.type === FRUIT || yetAnotherObject.type === POISON_FRUIT) { + // not pushable + return false; + } + if (yetAnotherObject === pusher) { + // indirect pushing ourselves. + // special check for when we're indirectly pushing the tip of our own tail. + if (forwardLocation === pusher.locations[pusher.locations.length - 1]) { + // for some reason this is ok. ------------ THIS IS THE TAIL GLITCH + continue; + } + return false; + } + addIfNotPresent(pushedObjects, yetAnotherObject); + if (level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work + } else + addIfNotPresent(forwardLocations, forwardLocation); } - addIfNotPresent(pushedObjects, yetAnotherObject); - if(level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work - } else - addIfNotPresent(forwardLocations, forwardLocation); } - } - // check forward locations - for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform, saw no effect but left new code - var forwardLocation = forwardLocations[i]; - // many of these locations can be inside objects, - // but that means the tile must be air, - // and we already know pushing that object. - var tileCode = level.map[forwardLocation]; - var object = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); - if (!isTileCodeAir(pusher, object, tileCode, dr, dc)) { - if (dyingObjects != null) { - if (tileCode === SPIKE) { - // uh... which object was this again? - if (object.type === SNAKE) { - // ouch! - addIfNotPresent(dyingObjects, object); - continue; - } - - } - else if (tileCode === LAVA) { - if (object.type === SNAKE || object.type === BLOCK) { - addIfNotPresent(dyingObjects, object); - continue; - } - } - else if (tileCode === WATER) { - if (object.type === BLOCK) { - addIfNotPresent(dyingObjects, object); - continue; + // check forward locations + for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform, saw no effect but left new code + var forwardLocation = forwardLocations[i]; + // many of these locations can be inside objects, + // but that means the tile must be air, + // and we already know pushing that object. + var tileCode = level.map[forwardLocation]; + var object = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); + if (!isTileCodeAir(pusher, object, tileCode, dr, dc)) { + if (dyingObjects != null) { + if (tileCode === SPIKE) { + // uh... which object was this again? + if (object.type === SNAKE) { + // ouch! + addIfNotPresent(dyingObjects, object); + continue; + } + + } + else if (tileCode === LAVA) { + if (object.type === SNAKE || object.type === BLOCK) { + addIfNotPresent(dyingObjects, object); + continue; + } + } + else if (tileCode === WATER) { + if (object.type === BLOCK) { + addIfNotPresent(dyingObjects, object); + continue; + } + } } + // can't push into something solid + return false; } - } - // can't push into something solid - return false; } - } - // the push is go - return true; + // the push is go + return true; } function activateAnySnakePlease() { - var snakes = getSnakes(); - if (snakes.length === 0) return; // nope.avi - activeSnakeId = snakes[0].id; + var snakes = getSnakes(); + if (snakes.length === 0) return; // nope.avi + activeSnakeId = snakes[0].id; } function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations, changeLog, animations) { - objects.forEach(function(object) { - var oldState = serializeObjectState(object); - var oldPortals = getSetIntersection(portalLocations, object.locations); - for (var i = 0; i < object.locations.length; i++) { - object.locations[i] = offsetLocation(object.locations[i], dr, dc); - if (level.map[object.locations[i]] == BUBBLE || level.map[object.locations[i]] == CLOUD) - paintTileAtLocation(object.locations[i], SPACE, changeLog); - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - animations.push([ - "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK - object.id, - dr, - dc, - ]); - - var newPortals = getSetIntersection(portalLocations, object.locations); - var activatingPortals = newPortals.filter(function(portalLocation) { - return oldPortals.indexOf(portalLocation) === -1; + objects.forEach(function (object) { + var oldState = serializeObjectState(object); + var oldPortals = getSetIntersection(portalLocations, object.locations); + for (var i = 0; i < object.locations.length; i++) { + object.locations[i] = offsetLocation(object.locations[i], dr, dc); + if (level.map[object.locations[i]] == BUBBLE || level.map[object.locations[i]] == CLOUD) + paintTileAtLocation(object.locations[i], SPACE, changeLog); + } + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + animations.push([ + "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK + object.id, + dr, + dc, + ]); + + var newPortals = getSetIntersection(portalLocations, object.locations); + var activatingPortals = newPortals.filter(function (portalLocation) { + return oldPortals.indexOf(portalLocation) === -1; + }); + if (activatingPortals.length === 1) { + // exactly one new portal we're touching. activate it + portalActivationLocations.push(activatingPortals[0]); + } }); - if (activatingPortals.length === 1) { - // exactly one new portal we're touching. activate it - portalActivationLocations.push(activatingPortals[0]); - } - }); } function activatePortal(portalLocations, portalLocation, animations, changeLog) { - var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; - var portalRowcol = getRowcol(level, portalLocation); - var otherPortalRowcol = getRowcol(level, otherPortalLocation); - var delta = {r:otherPortalRowcol.r - portalRowcol.r, c:otherPortalRowcol.c - portalRowcol.c}; - - var object = findObjectAtLocation(portalLocation); - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r + delta.r; - var c = rowcol.c + delta.c; - if (!isInBounds(level, r, c)) return false; // out of bounds - newLocations.push(getLocation(level, r, c)); - } - - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile - var otherObject = findObjectAtLocation(location); - if (otherObject != null && otherObject !== object) return; // blocked by object - } - - // zappo presto! - var oldState = serializeObjectState(object); - object.locations = newLocations; - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (level.map[location] == BUBBLE || level.map[location] == CLOUD) //changed this despite bubble working perfectly without it - paintTileAtLocation(location, SPACE, changeLog); - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; + var portalRowcol = getRowcol(level, portalLocation); + var otherPortalRowcol = getRowcol(level, otherPortalLocation); + var delta = { r: otherPortalRowcol.r - portalRowcol.r, c: otherPortalRowcol.c - portalRowcol.c }; + + var object = findObjectAtLocation(portalLocation); + var newLocations = []; + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r + delta.r; + var c = rowcol.c + delta.c; + if (!isInBounds(level, r, c)) return false; // out of bounds + newLocations.push(getLocation(level, r, c)); + } + + for (var i = 0; i < newLocations.length; i++) { + var location = newLocations[i]; + if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile + var otherObject = findObjectAtLocation(location); + if (otherObject != null && otherObject !== object) return; // blocked by object + } + + // zappo presto! + var oldState = serializeObjectState(object); + object.locations = newLocations; + for (var i = 0; i < newLocations.length; i++) { + var location = newLocations[i]; + if (level.map[location] == BUBBLE || level.map[location] == CLOUD) //changed this despite bubble working perfectly without it + paintTileAtLocation(location, SPACE, changeLog); + } + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); } function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { - switch (tileCode) - { - case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; - case WOODPLATFORM: case BUBBLE: return pusher != null; - case PLATFORM: return dr != 1; - case ONEWAYWALLU: return dr != 1; - case ONEWAYWALLD: return dr != -1; - case ONEWAYWALLL: return dc != 1; - case ONEWAYWALLR: return dc != -1; - default: return false; - } + switch (tileCode) { + case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; + case WOODPLATFORM: case BUBBLE: return pusher != null; + case PLATFORM: return dr != 1; + case ONEWAYWALLU: return dr != 1; + case ONEWAYWALLD: return dr != -1; + case ONEWAYWALLL: return dc != 1; + case ONEWAYWALLR: return dc != -1; + default: return false; + } } function addIfNotPresent(array, element) { - if (array.indexOf(element) !== -1) return; - array.push(element); + if (array.indexOf(element) !== -1) return; + array.push(element); } function removeAnyObjectAtLocation(location, changeLog) { - var object = findObjectAtLocation(location); - if (object != null) removeObject(object, changeLog); + var object = findObjectAtLocation(location); + if (object != null) removeObject(object, changeLog); } function removeAnimatedObject(object, changeLog) { - removeObject(object, changeLog); - freshlyRemovedAnimatedObjects.push(object); + removeObject(object, changeLog); + freshlyRemovedAnimatedObjects.push(object); } function removeObject(object, changeLog) { - removeFromArray(level.objects, object); - changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0,[]]]); - if (object.type === SNAKE && object.id === activeSnakeId) { - activateAnySnakePlease(); - } - if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { - // no longer editing an object that doesn't exit - paintBrushBlockId = null; - } - if (object.type === BLOCK) { - delete blockSupportRenderCache[object.id]; - } + removeFromArray(level.objects, object); + changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0, []]]); + if (object.type === SNAKE && object.id === activeSnakeId) { + activateAnySnakePlease(); + } + if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { + // no longer editing an object that doesn't exit + paintBrushBlockId = null; + } + if (object.type === BLOCK) { + delete blockSupportRenderCache[object.id]; + } } function removeFromArray(array, element) { - var index = array.indexOf(element); - if (index === -1) throw unreachable(); - array.splice(index, 1); + var index = array.indexOf(element); + if (index === -1) throw unreachable(); + array.splice(index, 1); } function findActiveSnake() { - var snakes = getSnakes(); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) return snakes[i]; - } - throw unreachable(); + var snakes = getSnakes(); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) return snakes[i]; + } + throw unreachable(); } function findBlockById(id) { - return findObjectOfTypeAndId(BLOCK, id); + return findObjectOfTypeAndId(BLOCK, id); } function findSnakesOfColor(color) { - return level.objects.filter(function(object) { - if (object.type !== SNAKE) return false; - return object.id % snakeColors.length === color; - }); + return level.objects.filter(function (object) { + if (object.type !== SNAKE) return false; + return object.id % snakeColors.length === color; + }); } function findObjectOfTypeAndId(type, id) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.type === type && object.id === id) return object; - } - return null; + for (var i = 0; i < level.objects.length; i++) { + var object = level.objects[i]; + if (object.type === type && object.id === id) return object; + } + return null; } function findObjectAtLocation(location) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.locations.indexOf(location) !== -1) - return object; - } - return null; + for (var i = 0; i < level.objects.length; i++) { + var object = level.objects[i]; + if (object.locations.indexOf(location) !== -1) + return object; + } + return null; } function isUneatenFruit() { - return getObjectsOfType(FRUIT).length > 0 || getObjectsOfType(POISON_FRUIT).length > 0; + return getObjectsOfType(FRUIT).length > 0 || getObjectsOfType(POISON_FRUIT).length > 0; } function getActivePortalLocations() { - var portalLocations = getPortalLocations(); - if (portalLocations.length !== 2) return []; // nice try - return portalLocations; + var portalLocations = getPortalLocations(); + if (portalLocations.length !== 2) return []; // nice try + return portalLocations; } function getPortalLocations() { - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === PORTAL) result.push(i); - } - return result; + var result = []; + for (var i = 0; i < level.map.length; i++) { + if (level.map[i] === PORTAL) result.push(i); + } + return result; } function countSnakes() { - return getSnakes().length; + return getSnakes().length; } function getSnakes() { - return getObjectsOfType(SNAKE); + return getObjectsOfType(SNAKE); } function getBlocks() { - return getObjectsOfType(BLOCK); + return getObjectsOfType(BLOCK); } -function getOccupiedClosedLiftLocations() -{ - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === CLOSEDLIFT) { - if (findObjectAtLocation(i)) - result.push(i); +function getOccupiedClosedLiftLocations() { + var result = []; + for (var i = 0; i < level.map.length; i++) { + if (level.map[i] === CLOSEDLIFT) { + if (findObjectAtLocation(i)) + result.push(i); + } } - } - return result; + return result; } function getObjectsOfType(type) { - return level.objects.filter(function(object) { - return object.type == type; - }); + return level.objects.filter(function (object) { + return object.type == type; + }); } function isDead() { - if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; - return getSnakes().filter(function(snake) { - return !!snake.dead; - }).length > 0; + if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; + return getSnakes().filter(function (snake) { + return !!snake.dead; + }).length > 0; } function isAlive() { - return countSnakes() > 0 && !isDead(); + return countSnakes() > 0 && !isDead(); } var activeSnakeId = null; @@ -2334,22 +2317,22 @@ var DIE_SNAKE = "ds"; var DIE_BLOCK = "db"; var INFINITE_LOOP = "il"; var animationQueue = [ - // // sequence of disjoint animation groups. - // // each group completes before the next begins. - // [ - // 70, // duration of this animation group - // // multiple things to animate simultaneously - // [ - // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, - // objectId, - // dr, - // dc, - // ], - // [ - // INFINITE_LOOP, - // loopSizeNotIncludingThis, - // ], - // ], + // // sequence of disjoint animation groups. + // // each group completes before the next begins. + // [ + // 70, // duration of this animation group + // // multiple things to animate simultaneously + // [ + // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, + // objectId, + // dr, + // dc, + // ], + // [ + // INFINITE_LOOP, + // loopSizeNotIncludingThis, + // ], + // ], ]; var animationQueueCursor = 0; var animationStart = null; // new Date().getTime() @@ -2359,33 +2342,33 @@ var freshlyRemovedAnimatedObjects = []; // render the support beams for blocks into a temporary buffer, and remember it. // this is due to stencil buffers causing slowdown on some platforms. see #25. var blockSupportRenderCache = { - // id: canvas, - // "0": document.createElement("canvas"), + // id: canvas, + // "0": document.createElement("canvas"), }; function render() { - if (level == null) return; - if (animationQueueCursor < animationQueue.length) { - var animationDuration = animationQueue[animationQueueCursor][0]; - animationProgress = (new Date().getTime() - animationStart) / animationDuration; - if (animationProgress >= 1.0) { - // animation group complete - animationProgress -= 1.0; - animationQueueCursor++; - if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { - var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; - animationQueueCursor -= infiniteLoopSize; - } - animationStart = new Date().getTime(); + if (level == null) return; + if (animationQueueCursor < animationQueue.length) { + var animationDuration = animationQueue[animationQueueCursor][0]; + animationProgress = (new Date().getTime() - animationStart) / animationDuration; + if (animationProgress >= 1.0) { + // animation group complete + animationProgress -= 1.0; + animationQueueCursor++; + if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { + var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; + animationQueueCursor -= infiniteLoopSize; + } + animationStart = new Date().getTime(); + } } - } - if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; - canvas.width = tileSize * level.width; - canvas.height = tileSize * level.height; - var context = canvas.getContext("2d"); //Gooby - - themeName = themes[themeCounter][0]; - if(themeName!="sky"){ + if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; + canvas.width = tileSize * level.width; + canvas.height = tileSize * level.height; + var context = canvas.getContext("2d"); + + themeName = themes[themeCounter][0]; + if (themeName != "sky") { background = themes[themeCounter][1]; material = themes[themeCounter][2]; surface = themes[themeCounter][3]; @@ -2396,786 +2379,802 @@ function render() { fruitColors = themes[themeCounter][8]; textStyle = themes[themeCounter][10]; experimentalColors = themes[themeCounter][11]; - - if(background.substr(0,1) == "#") { + + if (background.substr(0, 1) == "#") { context.fillStyle = background; context.fillRect(0, 0, canvas.width, canvas.height); } - else{ - for(var i = 0; i maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var image = blockSupportRenderCache[object.id]; - if (image == null) { - // render the support beams to a buffer - blockSupportRenderCache[object.id] = image = document.createElement("canvas"); - image.width = (maxC - minC + 1) * tileSize; - image.height = (maxR - minR + 1) * tileSize; - var bufferContext = image.getContext("2d"); - // Make a stencil that excludes the insides of blocks. - // Then when we render the support beams, we won't see the supports inside the block itself. - bufferContext.beginPath(); - // Draw a path around the whole screen in the opposite direction as the rectangle paths below. - // This means that the below rectangles will be removing area from the greater rectangle. - bufferContext.rect(image.width, 0, -image.width, image.height); - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r - minR; - var c = rowcol.c - minC; - bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); - } - bufferContext.clip(); - for (var i = 0; i < object.locations.length - 1; i++) { - var rowcol1 = getRowcol(level, object.locations[i]); - rowcol1.r -= minR; - rowcol1.c -= minC; - var rowcol2 = getRowcol(level, object.locations[i + 1]); - rowcol2.r -= minR; - rowcol2.c -= minC; - var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; - drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - } - } - var r = minR + animationDisplacementRowcol.r; - var c = minC + animationDisplacementRowcol.c; - context.drawImage(image, c * tileSize, r * tileSize); - }); - - if(!cs) { - // terrain - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - var tileCode = level.map[location]; - drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids + + // active snake halo + /*if (countSnakes() !== 0 && isAlive()) { + var activeSnake = findActiveSnake(); + var activeSnakeRowcol = getRowcol(level, activeSnake.locations[0]); + drawCircle(activeSnakeRowcol.r, activeSnakeRowcol.c, 2, "rgba(256,256,256,0.3)"); + }*/ + + if (persistentState.showEditor) { + if (paintBrushTileCode === BLOCK) { + if (paintBrushBlockId != null) { + // fade everything else away + context.fillStyle = "rgba(0, 0, 0, 0.8)"; + context.fillRect(0, 0, canvas.width, canvas.height); + // and render just this object in focus + var activeBlock = findBlockById(paintBrushBlockId); + renderLevel([activeBlock]); } - } + } else if (paintBrushTileCode === "select") { + getSelectedLocations().forEach(function (location) { + var rowcol = getRowcol(level, location); + drawRect(rowcol.r, rowcol.c, "rgba(128, 128, 128, 0.3)"); + }); } + } - for(var i = 0; i maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var image = blockSupportRenderCache[object.id]; + if (image == null) { + // render the support beams to a buffer + blockSupportRenderCache[object.id] = image = document.createElement("canvas"); + image.width = (maxC - minC + 1) * tileSize; + image.height = (maxR - minR + 1) * tileSize; + var bufferContext = image.getContext("2d"); + // Make a stencil that excludes the insides of blocks. + // Then when we render the support beams, we won't see the supports inside the block itself. + bufferContext.beginPath(); + // Draw a path around the whole screen in the opposite direction as the rectangle paths below. + // This means that the below rectangles will be removing area from the greater rectangle. + bufferContext.rect(image.width, 0, -image.width, image.height); + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r - minR; + var c = rowcol.c - minC; + bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); + } + bufferContext.clip(); + for (var i = 0; i < object.locations.length - 1; i++) { + var rowcol1 = getRowcol(level, object.locations[i]); + rowcol1.r -= minR; + rowcol1.c -= minC; + var rowcol2 = getRowcol(level, object.locations[i + 1]); + rowcol2.r -= minR; + rowcol2.c -= minC; + var cornerRowcol = { r: rowcol1.r, c: rowcol2.c }; + var connectorColor = tint(blockColors[object.id % blockColors.length], .5); + drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, connectorColor); + drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, connectorColor); + } + } + var r = minR + animationDisplacementRowcol.r; + var c = minC + animationDisplacementRowcol.c; + context.drawImage(image, c * tileSize, r * tileSize); + }); - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - location = getLocation(level, r, c); - tileCode = level.map[location]; - if(tileCode === WALL) drawTile(tileCode, r, c, level, location, false); //draws only walls + if (!cs) { + // terrain + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + var tileCode = level.map[location]; + drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids + } + } } - } - } - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - location = getLocation(level, r, c); - tileCode = level.map[location]; - if(tileCode === CLOUD || tileCode === LAVA || tileCode === WATER) drawTile(tileCode, r, c, level, location, false); //draws only clouds + for (var i = 0; i < objects.length; i++) { + var object = objects[i]; + if (object.type === SNAKE || object.type === BLOCK) drawObject(object); //draws snakes and blocks + } + + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + location = getLocation(level, r, c); + tileCode = level.map[location]; + if (tileCode === WALL) drawTile(tileCode, r, c, level, location, false); //draws only walls + } + } + } + + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + location = getLocation(level, r, c); + tileCode = level.map[location]; + if (tileCode === CLOUD || tileCode === LAVA || tileCode === WATER) drawTile(tileCode, r, c, level, location, false); //draws only clouds + } + } } - } - } - for(var i = 0; i6) { color= color.substring(1,color.length)} - var rgb = parseInt(color, 16); - var r = Math.abs(((rgb >> 16) & 0xFF)+v); if (r>255) r=r-(r-255); - var g = Math.abs(((rgb >> 8) & 0xFF)+v); if (g>255) g=g-(g-255); - var b = Math.abs((rgb & 0xFF)+v); if (b>255) b=b-(b-255); - r = Number(r < 0 || isNaN(r)) ? 0 : ((r > 255) ? 255 : r).toString(16); - if (r.length == 1) r = '0' + r; - g = Number(g < 0 || isNaN(g)) ? 0 : ((g > 255) ? 255 : g).toString(16); - if (g.length == 1) g = '0' + g; - b = Number(b < 0 || isNaN(b)) ? 0 : ((b > 255) ? 255 : b).toString(16); - if (b.length == 1) b = '0' + b; - return "#" + r + g + b; -} - - function drawObject(object) { - switch (object.type) { - case SNAKE: - var falling = false; - var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); - if (animationDisplacementRowcol.r != 0) falling = true; - var lastRowcol = null - var nextRowcol = null - var color = snakeColors[object.id % snakeColors.length]; - var colorIndex = object.id % snakeColors.length; - var altColor = getTintedColor(color, 50); - if(themeName==="Classic") altColor = color; - var headRowcol; - var orientation = 10; - for (var i = 0; i < object.locations.length; i++) { - var animation; - var rowcol; - if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward - rowcol = getRowcol(level, object.locations[i]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else if (i === object.locations.length) { - // animated tail? - if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { - // animate tail slithering to catch up - rowcol = getRowcol(level, object.locations[i-1]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else { - // no animated tail needed - break; - } - } else rowcol = getRowcol(level, object.locations[i]); - - lastRowcol = getRowcol(level, object.locations[i-1]); //closer to head - nextRowcol = getRowcol(level, object.locations[i+1]); //closer to tail - var rc = rowcol; - var lrc = lastRowcol; - var nrc = nextRowcol; - - if (object.dead) { //if snake dies after moving left or right, head is positioned down - rowcol.r += .5; - lastRowcol.r += .5; - nextRowcol.r += .5; - falling = true; - } - rowcol.r += animationDisplacementRowcol.r; - rowcol.c += animationDisplacementRowcol.c; - lastRowcol.r += animationDisplacementRowcol.r; - lastRowcol.c += animationDisplacementRowcol.c; - nextRowcol.r += animationDisplacementRowcol.r; - nextRowcol.c += animationDisplacementRowcol.c; - - var cx = rowcol.c * tileSize; - var cy = rowcol.r * tileSize; - - if (i === 0) { - context.fillStyle = color; - headRowcol = rowcol; - - //determines orientation of face - if(!falling) nextRowcol = getRowcol(level, object.locations[1]); - if (nextRowcol.r < rowcol.r) { //last move down - roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false); //draw head - if(colorIndex === 0) orientation = 2; - else if(colorIndex === 1) orientation = 6; - else if(colorIndex === 2) orientation = 3; - else if(colorIndex === 3) orientation = 5; - } - else if (nextRowcol.r > rowcol.r) { //last move up - roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false); //draw head - if(colorIndex === 0) orientation = 0; - else if(colorIndex === 1) orientation = 4; - else if(colorIndex === 2) orientation = 1; - else if(colorIndex === 3) orientation = 7; - } - else if (nextRowcol.c < rowcol.c) { //last move right - roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false); //draw head - if(colorIndex === 0) orientation = 1; - else if(colorIndex === 1) orientation = 5; - else if(colorIndex === 2) orientation = 2; - else if(colorIndex === 3) orientation = 4; - } - else if (nextRowcol.c > rowcol.c) { //last move left - roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false); //draw head - if(colorIndex === 0) orientation = 3; - else if(colorIndex === 1) orientation = 7; - else if(colorIndex === 2) orientation = 0; - else if(colorIndex === 3) orientation = 6; + + function tint(hex, delta) { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + + var r = parseInt(result[1], 16); + var g = parseInt(result[2], 16); + var b = parseInt(result[3], 16); + + r /= 255, g /= 255, b /= 255; + var max = Math.max(r, g, b), min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if (max == min) { + h = s = 0; // achromatic + } else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch (max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; } - else { - roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); //draw head - orientation = 10; - } - } else { - if(i % 2 == 0) context.fillStyle = color; - else context.fillStyle = altColor; - - if (i === object.locations.length-1) { - if(lastRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false);} - else if(lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false);} - else if(lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false);} - else if(lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false);} + h /= 6; + } + + s = s * 100; + s = Math.round(s); + l = l * 100 * delta; + l = Math.round(l); + h = Math.round(360 * h); + + return 'hsl(' + h + ', ' + s + '%, ' + l + '%)'; + } + + function drawObject(object) { + switch (object.type) { + case SNAKE: + var falling = false; + var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); + if (animationDisplacementRowcol.r != 0) falling = true; + var lastRowcol = null + var nextRowcol = null + var color = snakeColors[object.id % snakeColors.length]; + var colorIndex = object.id % snakeColors.length; + var altColor = tint(color, 1.2); + if (themeName === "Classic") altColor = color; + var headRowcol; + var orientation = 10; + for (var i = 0; i < object.locations.length; i++) { + var animation; + var rowcol; + if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward + rowcol = getRowcol(level, object.locations[i]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else if (i === object.locations.length) { + // animated tail? + if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { + // animate tail slithering to catch up + rowcol = getRowcol(level, object.locations[i - 1]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else { + // no animated tail needed + break; + } + } else rowcol = getRowcol(level, object.locations[i]); + + lastRowcol = getRowcol(level, object.locations[i - 1]); //closer to head + nextRowcol = getRowcol(level, object.locations[i + 1]); //closer to tail + var rc = rowcol; + var lrc = lastRowcol; + var nrc = nextRowcol; + + if (object.dead) { //if snake dies after moving left or right, head is positioned down + rowcol.r += .5; + lastRowcol.r += .5; + nextRowcol.r += .5; + falling = true; + } + rowcol.r += animationDisplacementRowcol.r; + rowcol.c += animationDisplacementRowcol.c; + lastRowcol.r += animationDisplacementRowcol.r; + lastRowcol.c += animationDisplacementRowcol.c; + nextRowcol.r += animationDisplacementRowcol.r; + nextRowcol.c += animationDisplacementRowcol.c; + + var cx = rowcol.c * tileSize; + var cy = rowcol.r * tileSize; + + if (i === 0) { + context.fillStyle = color; + headRowcol = rowcol; + + //determines orientation of face + if (!falling) nextRowcol = getRowcol(level, object.locations[1]); + if (nextRowcol.r < rowcol.r) { //last move down + roundRect(context, cx, cy, tileSize, tileSize, { bl: 10, br: 10 }, true, false); //draw head + if (colorIndex === 0) orientation = 2; + else if (colorIndex === 1) orientation = 6; + else if (colorIndex === 2) orientation = 3; + else if (colorIndex === 3) orientation = 5; + } + else if (nextRowcol.r > rowcol.r) { //last move up + roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); //draw head + if (colorIndex === 0) orientation = 0; + else if (colorIndex === 1) orientation = 4; + else if (colorIndex === 2) orientation = 1; + else if (colorIndex === 3) orientation = 7; + } + else if (nextRowcol.c < rowcol.c) { //last move right + roundRect(context, cx, cy, tileSize, tileSize, { tr: 10, br: 10 }, true, false); //draw head + if (colorIndex === 0) orientation = 1; + else if (colorIndex === 1) orientation = 5; + else if (colorIndex === 2) orientation = 2; + else if (colorIndex === 3) orientation = 4; + } + else if (nextRowcol.c > rowcol.c) { //last move left + roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); //draw head + if (colorIndex === 0) orientation = 3; + else if (colorIndex === 1) orientation = 7; + else if (colorIndex === 2) orientation = 0; + else if (colorIndex === 3) orientation = 6; + } + else { + roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); //draw head + orientation = 10; + } + } else { + if (i % 2 == 0) context.fillStyle = color; + else context.fillStyle = altColor; + + if (i === object.locations.length - 1) { + if (lastRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); } + else if (lastRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10, br: 10 }, true, false); } + else if (lastRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10, br: 10 }, true, false); } + else if (lastRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); } + } + else if (i != object.locations.length - 1 && i != object.locations.length) { + if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10 }, true, false); } + else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10 }, true, false); } + else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { br: 10 }, true, false); } + else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10 }, true, false); } + + else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10 }, true, false); } + else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10 }, true, false); } + else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { br: 10 }, true, false); } + else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10 }, true, false); } + + else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, 0, true, false); } + } + else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); + } } - else if (i != object.locations.length-1 && i != object.locations.length) { - if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} - else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} - else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} - else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} - - else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} - else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} - else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} - else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} - - else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, 0, true, false);} + drawFace(object.id, headRowcol.c, headRowcol.r, orientation); + break; + case BLOCK: + drawBlock(object); + break; + case FRUIT: + case POISON_FRUIT: + var is_poison = object.type == POISON_FRUIT; + rowcol = getRowcol(level, object.locations[0]); + var c = rowcol.c; + var r = rowcol.r; + var startC = c * tileSize + tileSize / 2; + var startR = r * tileSize + tileSize * .2; + var resize = tileSize * 1.7; + var color = fruitColors[object.id % fruitColors.length]; + var stemColor = themes[themeCounter][9] + if (themeName === "Classic") color = "#f0f"; + if (is_poison) { color = "#556815"; stemColor = "black"; } + context.fillStyle = color; + if (themeName != "Classic") { + if (surface == "rainbow") { + context.fillStyle = "black"; + context.lineWidth = tileSize / 8; + context.strokeStyle = "white"; + resize = tileSize * 1.4; + } + //context.fillStyle = "#ff6b45"; + context.beginPath(); + context.moveTo(startC, startR); + context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC - resize * .25, startR - resize * .1, startC - resize * .3, startR + resize * .05); + context.bezierCurveTo(startC - resize * .35, startR + resize * .15, startC - resize * .3, startR + resize * .6, startC, startR + resize * .5); + context.bezierCurveTo(startC + resize * .3, startR + resize * .6, startC + resize * .35, startR + resize * .15, startC + resize * .3, startR + resize * .05); + context.bezierCurveTo(startC + resize * .25, startR - resize * .05, startC + resize * .1, startR - resize * .1, startC, startR); + context.closePath(); + context.fill(); + if (surface == "rainbow") context.stroke(); + + context.beginPath(); + context.moveTo(startC, startR); + context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC, startR - resize * .1, startC - resize * .1, startR - resize * .15); + context.bezierCurveTo(startC, startR - resize * .1, startC + resize * .05, startR - resize * .1, startC, startR); + context.fillStyle = stemColor; + context.fill(); } - else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); - } + else drawCircle(rowcol.r, rowcol.c, 1, color); + break; + default: throw unreachable(); } - drawFace(object.id, headRowcol.c, headRowcol.r, orientation); - break; - case BLOCK: - drawBlock(object); - break; - case FRUIT: - case POISON_FRUIT: - var is_poison = object.type == POISON_FRUIT; - rowcol = getRowcol(level, object.locations[0]); - var c = rowcol.c; - var r = rowcol.r; - var startC = c*tileSize+tileSize/2; - var startR = r*tileSize+tileSize*.2; - var resize = tileSize * 1.7; - var color = fruitColors[object.id % fruitColors.length]; - var stemColor = themes[themeCounter][9] - if (is_poison) { color = "#556815"; stemColor = "black";} //placeholder effect - context.fillStyle = color; - if(themeName != "Classic"){ - if(surface == "rainbow") { - context.fillStyle = "black"; - context.lineWidth = tileSize/8; - context.strokeStyle = "white"; - resize = tileSize * 1.4; - } - //context.fillStyle = "#ff6b45"; - context.beginPath(); - context.moveTo(startC, startR); - context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC-resize*.25, startR-resize*.1, startC-resize*.3, startR+resize*.05); - context.bezierCurveTo(startC-resize*.35, startR+resize*.15, startC-resize*.3, startR+resize*.6, startC, startR+resize*.5); - context.bezierCurveTo(startC+resize*.3, startR+resize*.6, startC+resize*.35, startR+resize*.15, startC+resize*.3, startR+resize*.05); - context.bezierCurveTo(startC+resize*.25, startR-resize*.05, startC+resize*.1, startR-resize*.1, startC, startR); - context.closePath(); - context.fill(); - if(surface == "rainbow") context.stroke(); + } - context.beginPath(); - context.moveTo(startC,startR); - context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); - context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); - context.fillStyle = stemColor; - context.fill(); + function drawPlatform(r, c, adjacentTiles) { + newPlatform(r, c, isPlatform); + + function isPlatform(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === PLATFORM; } - else drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); - break; - default: throw unreachable(); + + /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*1, r*tileSize); + context.lineTo(c*tileSize, r*tileSize); + context.closePath(); + context.rect(c*tileSize, r*tileSize+tileSize*.2857, tileSize, tileSize*.1429);*/ + + /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.25, r*tileSize+tileSize*.2, c*tileSize+tileSize*.25, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.75, r*tileSize+tileSize*.2, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.lineTo((c+1)*tileSize, r*tileSize); + context.lineTo(c*tileSize, r*tileSize);*/ + + /*context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.arc((c + 3/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.arc((c + 1/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.lineTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize+tileSize, r*tileSize);*/ + + //context.closePath(); + //context.fillStyle = "#000066"; + //ontext.fill(); + //context.stroke(); } - } - -function drawPlatform(r, c, adjacentTiles) { - newPlatform(r, c, isPlatform); - - function isPlatform(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === PLATFORM; + + function newPlatform(r, c, isOccupied) { + + var x1 = .05; + var x2 = .05; + if (isOccupied(-1, 0)) x1 = 0; + if (isOccupied(1, 0)) x2 = 0; + + var platformColors = ["#ffcccc", "#ffe0cc", "#ffffcc", "#e6ffe6", "#e6e6ff"]; + for (var i = 0; i < 5; i++) { + var j = i - 1; + if (j < 0) j = 0; + context.beginPath(); + context.moveTo(c * tileSize + tileSize * (i * x1), r * tileSize + tileSize * (.05 + (.1 * i) - (j * .02))); + context.strokeStyle = platformColors[i]; + context.lineWidth = tileSize * (.1 - (i * .02)); + context.lineTo(c * tileSize + tileSize * (1 - (i * x2)), r * tileSize + tileSize * (.05 + (.1 * i) - (j * .02))); + context.stroke(); + } } - - /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*1, r*tileSize); - context.lineTo(c*tileSize, r*tileSize); - context.closePath(); - context.rect(c*tileSize, r*tileSize+tileSize*.2857, tileSize, tileSize*.1429);*/ - - /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.25, r*tileSize+tileSize*.2, c*tileSize+tileSize*.25, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.75, r*tileSize+tileSize*.2, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo((c+1)*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize);*/ - - /*context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.arc((c + 3/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.arc((c + 1/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.lineTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize, r*tileSize);*/ - - //context.closePath(); - //context.fillStyle = "#000066"; - //ontext.fill(); - //context.stroke(); -} - -function newPlatform(r, c, isOccupied){ - - var x1 = .05; - var x2 = .05; - if(isOccupied(-1,0)) x1 = 0; - if(isOccupied(1,0)) x2 = 0; - - var platformColors = ["#ffcccc", "#ffe0cc", "#ffffcc", "#e6ffe6", "#e6e6ff"]; - for(var i = 0; i<5; i++){ - var j = i-1; - if(j<0) j = 0; + + function drawOneWayWall(fillStyle, r, c, dr, dc) { + context.lineWidth = 2; + context.strokeStyle = "#333"; context.beginPath(); - context.moveTo(c*tileSize+tileSize*(i*x1), r*tileSize+tileSize*(.05 + (.1 * i) - (j * .02))); - context.strokeStyle = platformColors[i]; - context.lineWidth = tileSize*(.1-(i*.02)); - context.lineTo(c*tileSize+tileSize*(1-(i*x2)), r*tileSize+tileSize*(.05 + (.1 * i) - (j * .02))); + + if (dr == -1) { + context.moveTo(c * tileSize, r * tileSize + tileSize / 2); + context.lineTo(c * tileSize + tileSize / 4, r * tileSize + tileSize / 4); + context.stroke(); + context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + tileSize / 4); + context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize / 2); + } + else if (dr == 1) { + context.moveTo(c * tileSize, r * tileSize + tileSize / 2); + context.lineTo(c * tileSize + tileSize / 4, r * tileSize + 3 * tileSize / 4); + context.stroke(); + context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + 3 * tileSize / 4); + context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize / 2); + } + else if (dc == -1) { + context.moveTo(c * tileSize + tileSize / 2, r * tileSize); + context.lineTo(c * tileSize + tileSize / 4, r * tileSize + tileSize / 4); + context.stroke(); + context.moveTo(c * tileSize + tileSize / 4, r * tileSize + 3 * tileSize / 4); + context.lineTo(c * tileSize + tileSize / 2, r * tileSize + tileSize); + } + else if (dc == 1) { + context.moveTo(c * tileSize + tileSize / 2, r * tileSize); + context.lineTo(c * tileSize + 3 * tileSize / 4, r * tileSize + tileSize / 4); + context.stroke(); + context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + 3 * tileSize / 4); + context.lineTo(c * tileSize + tileSize / 2, r * tileSize + tileSize); + } + context.stroke(); + context.lineWidth = 0; + + context.fillStyle = fillStyle; + if (dr == -1) roundRect(context, c * tileSize - tileSize / 15, r * tileSize - tileSize / 15, tileSize + 2 * tileSize / 15, tileSize / 4 + 2 * tileSize / 15, 2, true, false); + else if (dr == 1) roundRect(context, c * tileSize - tileSize / 15, (r + 1) * tileSize - tileSize / 15 - tileSize / 4, tileSize + 2 * tileSize / 15, tileSize / 4 + 2 * tileSize / 15, 2, true, false); + else if (dc == -1) roundRect(context, c * tileSize - tileSize / 15, r * tileSize - tileSize / 15, tileSize / 4 + 2 * tileSize / 15, tileSize + 2 * tileSize / 15, 2, true, false); + else if (dc == 1) roundRect(context, (c + 1) * tileSize - tileSize / 15 - tileSize / 4, r * tileSize - tileSize / 15, tileSize / 4 + 2 * tileSize / 15, tileSize + 2 * tileSize / 15, 2, true, false); } -} - - function drawOneWayWall(fillStyle, r, c, dr, dc) { - context.lineWidth = 2; - context.strokeStyle = "#333"; - context.beginPath(); - - if (dr == -1) { - context.moveTo(c * tileSize, r * tileSize + tileSize/2); - context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); - context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); - } - else if (dr == 1) { - context.moveTo(c * tileSize, r * tileSize + tileSize/2); - context.lineTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); - context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); - } - else if (dc == -1) { - context.moveTo(c * tileSize + tileSize/2, r * tileSize); - context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); - context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); - } - else if (dc == 1) { - context.moveTo(c * tileSize + tileSize/2, r * tileSize); - context.lineTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); - context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); - } - - context.stroke(); - context.lineWidth = 0; - - context.fillStyle = fillStyle; - if (dr == -1) roundRect(context, c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15, 2, true, false); - else if (dr == 1) roundRect(context, c * tileSize - tileSize/15, (r + 1) * tileSize - tileSize/15 - tileSize/4, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15, 2, true, false); - else if (dc == -1) roundRect(context, c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15, 2, true, false); - else if (dc == 1) roundRect(context, (c + 1) * tileSize - tileSize/15 - tileSize/4, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15, 2, true, false); - } - - function drawBubble(r, c) { - bubbleX = c*tileSize; - var grd = context.createRadialGradient(bubbleX, r*tileSize, 0, bubbleX, r*tileSize, tileSize); - grd.addColorStop(0, "rgba(255,255,255,.9)"); - grd.addColorStop(1, "rgba(255,255,255,.2)"); - context.fillStyle = grd; - context.lineWidth = .5; - context.strokeStyle = "rgba(200,200,200,.2)"; - - context.beginPath(); - context.arc(c*tileSize+tileSize*.5, r*tileSize+tileSize*.5, tileSize/2, 0, 2*Math.PI); - context.fill(); - context.stroke(); - } - -function drawLiquid(r, c, type, adjacentTiles) { - newLiquid(r, c, type, isSameLiquid); - - function isSameLiquid(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === type; - } -} - -function newLiquid(r, c, type, isOccupied){ - context.save(); - var tubColor; - if(type == LAVA) { - context.fillStyle = "#ffbf00"; - context.strokeStyle = "red"; - tubColor = "black"; - } - else { - context.fillStyle = "#1a8cff"; - context.strokeStyle = "#80ffe5"; - tubColor = "white"; + + function drawBubble(r, c) { + bubbleX = c * tileSize; + var grd = context.createRadialGradient(bubbleX, r * tileSize, 0, bubbleX, r * tileSize, tileSize); + grd.addColorStop(0, "rgba(255,255,255,.9)"); + grd.addColorStop(1, "rgba(255,255,255,.2)"); + context.fillStyle = grd; + context.lineWidth = .5; + context.strokeStyle = "rgba(200,200,200,.2)"; + + context.beginPath(); + context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, tileSize / 2, 0, 2 * Math.PI); + context.fill(); + context.stroke(); } - roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); - - context.lineWidth = 3; - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.1, c*tileSize+tileSize/3, r*tileSize+tileSize*.1, c*tileSize+tileSize/2, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.3, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.3, c*tileSize+tileSize, r*tileSize+tileSize*.2); - context.moveTo(c*tileSize, r*tileSize+tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.3, c*tileSize+tileSize/3, r*tileSize+tileSize*.3, c*tileSize+tileSize/2, r*tileSize+tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.5, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.5, c*tileSize+tileSize, r*tileSize+tileSize*.4); - context.moveTo(c*tileSize, r*tileSize+tileSize*.6); - context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.5, c*tileSize+tileSize/3, r*tileSize+tileSize*.5, c*tileSize+tileSize/2, r*tileSize+tileSize*.6); - context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.7, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.7, c*tileSize+tileSize, r*tileSize+tileSize*.6); - context.moveTo(c*tileSize, r*tileSize+tileSize*.8); - context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.7, c*tileSize+tileSize/3, r*tileSize+tileSize*.7, c*tileSize+tileSize/2, r*tileSize+tileSize*.8); - context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.9, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.9, c*tileSize+tileSize, r*tileSize+tileSize*.8); - context.stroke(); - - context.fillStyle = tubColor; - if(!isOccupied(-1,0)) { - if(isOccupied(-1,-1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize-tileSize*.2, tileSize*.2, tileSize*1.2, 0, true, false); - else roundRect(context, c*tileSize-tileSize*.1, r*tileSize, tileSize*.2, tileSize, 0, true, false); + + function drawLiquid(r, c, type, adjacentTiles) { + newLiquid(r, c, type, isSameLiquid); + + function isSameLiquid(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === type; + } } - if(!isOccupied(1,0)) roundRect(context, c*tileSize+tileSize*.9, r*tileSize, tileSize*.2, tileSize, 0, true, false); - if(!isOccupied(0,1)) { - if(isOccupied(-1,1) && !isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); - else if(!isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize*1.3, tileSize*.2, 0, true, false); - else if(isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); - else roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize, tileSize*.2, 0, true, false); + + function newLiquid(r, c, type, isOccupied) { + context.save(); + var tubColor; + if (type == LAVA) { + context.fillStyle = "#ffbf00"; + context.strokeStyle = "red"; + tubColor = "black"; + } + else { + context.fillStyle = "#1a8cff"; + context.strokeStyle = "#80ffe5"; + tubColor = "white"; + } + roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 0, true, false); + + context.lineWidth = 3; + context.beginPath(); + context.moveTo(c * tileSize, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .1, c * tileSize + tileSize / 3, r * tileSize + tileSize * .1, c * tileSize + tileSize / 2, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .3, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .3, c * tileSize + tileSize, r * tileSize + tileSize * .2); + context.moveTo(c * tileSize, r * tileSize + tileSize * .4); + context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .3, c * tileSize + tileSize / 3, r * tileSize + tileSize * .3, c * tileSize + tileSize / 2, r * tileSize + tileSize * .4); + context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .5, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .5, c * tileSize + tileSize, r * tileSize + tileSize * .4); + context.moveTo(c * tileSize, r * tileSize + tileSize * .6); + context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .5, c * tileSize + tileSize / 3, r * tileSize + tileSize * .5, c * tileSize + tileSize / 2, r * tileSize + tileSize * .6); + context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .7, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .7, c * tileSize + tileSize, r * tileSize + tileSize * .6); + context.moveTo(c * tileSize, r * tileSize + tileSize * .8); + context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .7, c * tileSize + tileSize / 3, r * tileSize + tileSize * .7, c * tileSize + tileSize / 2, r * tileSize + tileSize * .8); + context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .9, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .9, c * tileSize + tileSize, r * tileSize + tileSize * .8); + context.stroke(); + + context.fillStyle = tubColor; + if (!isOccupied(-1, 0)) { + if (isOccupied(-1, -1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize - tileSize * .2, tileSize * .2, tileSize * 1.2, 0, true, false); + else roundRect(context, c * tileSize - tileSize * .1, r * tileSize, tileSize * .2, tileSize, 0, true, false); + } + if (!isOccupied(1, 0)) roundRect(context, c * tileSize + tileSize * .9, r * tileSize, tileSize * .2, tileSize, 0, true, false); + if (!isOccupied(0, 1)) { + if (isOccupied(-1, 1) && !isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize + tileSize * .8, tileSize * 1.1, tileSize * .2, 0, true, false); + else if (!isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize, r * tileSize + tileSize * .8, tileSize * 1.3, tileSize * .2, 0, true, false); + else if (isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize + tileSize * .8, tileSize * 1.1, tileSize * .2, 0, true, false); + else roundRect(context, c * tileSize, r * tileSize + tileSize * .8, tileSize, tileSize * .2, 0, true, false); + } + context.restore(); } - context.restore(); -} - function drawLift(r, c, isFixed) { + function drawLift(r, c, isFixed) { context.lineWidth = .5; context.strokeStyle = "#777"; var strokeBool = false; - if(!isFixed) { + if (!isFixed) { context.fillStyle = "#e68a00"; - roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); + roundRect(context, c * tileSize + tileSize * .05, r * tileSize + tileSize, tileSize * .9, tileSize * .2, 2, true, strokeBool); context.fillStyle = "#cc0000"; - roundRect(context, c*tileSize+tileSize*.3, r*tileSize+tileSize*.8, tileSize*.4, tileSize*.2, {tl:2, tr:2}, true, strokeBool); + roundRect(context, c * tileSize + tileSize * .3, r * tileSize + tileSize * .8, tileSize * .4, tileSize * .2, { tl: 2, tr: 2 }, true, strokeBool); } - else if(isFixed) { + else if (isFixed) { context.fillStyle = "#e68a00"; - roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize*.8, tileSize*.9, tileSize*.2, 2, true, strokeBool); - roundRect(context, c*tileSize+tileSize*.05, r*tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); - + roundRect(context, c * tileSize + tileSize * .05, r * tileSize + tileSize * .8, tileSize * .9, tileSize * .2, 2, true, strokeBool); + roundRect(context, c * tileSize + tileSize * .05, r * tileSize, tileSize * .9, tileSize * .2, 2, true, strokeBool); + context.fillStyle = "#333"; - + context.beginPath(); - context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.45); - context.bezierCurveTo(c*tileSize+tileSize*.16,r*tileSize+tileSize*.45,c*tileSize+tileSize*.16,r*tileSize+tileSize*.55,c*tileSize+tileSize*.2,r*tileSize+tileSize*.55); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); + context.moveTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .8); + context.lineTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .5); + context.lineTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize * .7, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize * .2, r * tileSize + tileSize * .45); + context.bezierCurveTo(c * tileSize + tileSize * .16, r * tileSize + tileSize * .45, c * tileSize + tileSize * .16, r * tileSize + tileSize * .55, c * tileSize + tileSize * .2, r * tileSize + tileSize * .55); + context.lineTo(c * tileSize + tileSize * .7, r * tileSize + tileSize * .8); + context.lineTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .8); context.closePath(); context.fill(); - + context.beginPath(); - context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.45); - context.bezierCurveTo(c*tileSize+tileSize*.84,r*tileSize+tileSize*.45,c*tileSize+tileSize*.84,r*tileSize+tileSize*.55,c*tileSize+tileSize*.8,r*tileSize+tileSize*.55); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.8); + context.moveTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .8); + context.lineTo(c * tileSize + tileSize * .7, r * tileSize + tileSize * .5); + context.lineTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize * .8, r * tileSize + tileSize * .45); + context.bezierCurveTo(c * tileSize + tileSize * .84, r * tileSize + tileSize * .45, c * tileSize + tileSize * .84, r * tileSize + tileSize * .55, c * tileSize + tileSize * .8, r * tileSize + tileSize * .55); + context.lineTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .8); + context.lineTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .8); context.closePath(); context.fill(); - + /*context.beginPath(); context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.9); context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); @@ -3198,7 +3197,7 @@ function newLiquid(r, c, type, isOccupied){ context.closePath(); context.fill();*/ } - + /*var grd = context.createLinearGradient(c*tileSize, r*tileSize, (c+1)*tileSize, (r+1)*tileSize); grd.addColorStop(0, "rgba(255,255,255,.6)"); grd.addColorStop(.1, "rgba(255,255,255,.7)"); @@ -3304,37 +3303,35 @@ function newLiquid(r, c, type, isOccupied){ context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.2); context.stroke(); }*/ - } - - function drawWall(r, c, adjacentTiles) { //GOOBY - //drawRect(r, c, "#976537"); - drawTileNew(r, c, isWall, 0.2, material); - drawTileOutlines(r, c, isWall, 0.2, curlyOutline); - context.save(); - if(curlyOutline) drawBushes(r, c, isWall); - context.restore(); - context.fillStyle = "#895C33"; // dirt edge - //drawTileOutlines(r, c, isWall, 0.2, false); - - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; } - } - - function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle){ + + function drawWall(r, c, adjacentTiles) { + drawTileNew(r, c, isWall, 0.2, material); + drawTileOutlines(r, c, isWall, 0.2, curlyOutline); + context.save(); + if (curlyOutline) drawBushes(r, c, isWall); + context.restore(); + context.fillStyle = "#895C33"; // dirt edge + + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } + } + + function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle) { context.fillStyle = fillStyle; - if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10,br:10}, true, false); - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10}, true, false); - else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {br:10}, true, false); - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); - else roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); - + if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { bl: 10, br: 10 }, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tr: 10, br: 10 }, true, false); + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { bl: 10 }, true, false); + else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { br: 10 }, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tl: 10 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tr: 10 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 10, true, false); + else roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 0, true, false); + /*var randomSpot = Math.floor(Math.random() * 5); //random spots on dirt var randomColor = Math.floor(Math.random() * 5); context.beginPath(); @@ -3352,1062 +3349,1063 @@ function newLiquid(r, c, type, isOccupied){ } context.stroke();*/ } - - function drawCurves(r, c, adjacentTiles){ + + function drawCurves(r, c, adjacentTiles) { drawCurves2(r, c, isWall, material); - + function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; } } - - function drawCurves2(r, c, isOccupied, material){ + + function drawCurves2(r, c, isOccupied, material) { context.fillStyle = material; - if(isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { - context.fillRect((c+1)*tileSize, (r+1)*tileSize, tileSize/6, tileSize/6); + if (isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { + context.fillRect((c + 1) * tileSize, (r + 1) * tileSize, tileSize / 6, tileSize / 6); //context.globalCompositeOperation = "destination-out"; context.beginPath(); - context.arc((c+1)*tileSize+tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); + context.arc((c + 1) * tileSize + tileSize / 6, (r + 1) * tileSize + tileSize / 6, tileSize / 6, 0, 2 * Math.PI); context.closePath(); - + var bgColor; - if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*')+2, background.length); + if ((c + r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*') + 2, background.length); var r1, r2, b1, b2, g1, g2; - r1 = bgColor.substr(5, bgColor.indexOf(",")-5); - g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); - b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); - var shade = (r+1)*.03+.5; - if(shade>1) + r1 = bgColor.substr(5, bgColor.indexOf(",") - 5); + g1 = bgColor.substr(bgColor.indexOf(",") + 1, bgColor.indexOf(",") - 4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",") + 1) + 1, bgColor.indexOf(",") - 4); + var shade = (r + 1) * .03 + .5; + if (shade > 1) shade = 1; - r2 = 255 + (r1-255) * shade; - g2 = 255 + (g1-255) * shade; - b2 = 255 + (b1-255) * shade; + r2 = 255 + (r1 - 255) * shade; + g2 = 255 + (g1 - 255) * shade; + b2 = 255 + (b1 - 255) * shade; context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; context.fill(); - context.globalCompositeOperation = "source-over"; + context.globalCompositeOperation = "source-over"; } - if(isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1) && curlyOutline) { - context.fillRect(c*tileSize-tileSize/6, (r+1)*tileSize, tileSize/6, tileSize/6); + if (isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1) && curlyOutline) { + context.fillRect(c * tileSize - tileSize / 6, (r + 1) * tileSize, tileSize / 6, tileSize / 6); //context.globalCompositeOperation = "destination-out"; context.beginPath(); - context.arc(c*tileSize-tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); + context.arc(c * tileSize - tileSize / 6, (r + 1) * tileSize + tileSize / 6, tileSize / 6, 0, 2 * Math.PI); context.closePath(); - + var bgColor; - if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*')+2, background.length); + if ((c + r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*') + 2, background.length); var r1, r2, b1, b2, g1, g2; - r1 = bgColor.substr(5, bgColor.indexOf(",")-5); - g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); - b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); - var shade = (r+1)*.03+.5; - if(shade>1) + r1 = bgColor.substr(5, bgColor.indexOf(",") - 5); + g1 = bgColor.substr(bgColor.indexOf(",") + 1, bgColor.indexOf(",") - 4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",") + 1) + 1, bgColor.indexOf(",") - 4); + var shade = (r + 1) * .03 + .5; + if (shade > 1) shade = 1; - r2 = 255 + (r1-255) * shade; - g2 = 255 + (g1-255) * shade; - b2 = 255 + (b1-255) * shade; + r2 = 255 + (r1 - 255) * shade; + g2 = 255 + (g1 - 255) * shade; + b2 = 255 + (b1 - 255) * shade; context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; context.fill(); context.globalCompositeOperation = "source-over"; } } - - function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { //Gooby - if(surface != "rainbow") { - context.fillStyle = surface; - } - else{ - context.fillStyle = "white"; - var mod = (r+c) % 17; - switch(mod){ - case 0: context.fillStyle = "#ff004c"; break; - case 1: context.fillStyle = "#e30000"; break; - case 2: context.fillStyle = "#ff4c00"; break; - case 3: context.fillStyle = "#ff9900"; break; - case 4: context.fillStyle = "#ffe500"; break; - case 5: context.fillStyle = "#cbff00"; break; - case 6: context.fillStyle = "#7fff00"; break; - case 7: context.fillStyle = "#00ff19"; break; - case 8: context.fillStyle = "#00ff66"; break; - case 9: context.fillStyle = "#00ffb2"; break; - case 10: context.fillStyle = "#00ffff"; break; - case 11: context.fillStyle = "#00b2ff"; break; - case 12: context.fillStyle = "#3200ff"; break; - case 13: context.fillStyle = "#5702c6"; break; - case 14: context.fillStyle = "#cc00ff"; break; - case 15: context.fillStyle = "#ff00e5"; break; - case 16: context.fillStyle = "#ff0098"; break; - } - } - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - var complementPixels = (1 - 2 * outlineThickness) * tileSize; - - if (curlyOutline && !isOccupied(0, -1)){ - if(!isOccupied(-1, 0) && isOccupied(1, 0)){ - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.4, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize); - context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); - context.closePath(); + + function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { + if (surface != "rainbow") { + context.fillStyle = surface; } - else if(isOccupied(-1, 0) && !isOccupied(1, 0)){ - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.95, r*tileSize+tileSize*.3, c*tileSize+tileSize*.7, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.65, r*tileSize+tileSize*.4, c*tileSize+tileSize*.4, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.1, r*tileSize+tileSize*.4, c*tileSize, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize); - context.bezierCurveTo((c+1)*tileSize+tileSize*.2, r*tileSize-tileSize*.05, (c+1)*tileSize+tileSize*.15, r*tileSize+tileSize*.5, (c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.25); - context.closePath(); + else { + context.fillStyle = "white"; + var mod = (r + c) % 17; + switch (mod) { + case 0: context.fillStyle = "#ff004c"; break; + case 1: context.fillStyle = "#e30000"; break; + case 2: context.fillStyle = "#ff4c00"; break; + case 3: context.fillStyle = "#ff9900"; break; + case 4: context.fillStyle = "#ffe500"; break; + case 5: context.fillStyle = "#cbff00"; break; + case 6: context.fillStyle = "#7fff00"; break; + case 7: context.fillStyle = "#00ff19"; break; + case 8: context.fillStyle = "#00ff66"; break; + case 9: context.fillStyle = "#00ffb2"; break; + case 10: context.fillStyle = "#00ffff"; break; + case 11: context.fillStyle = "#00b2ff"; break; + case 12: context.fillStyle = "#3200ff"; break; + case 13: context.fillStyle = "#5702c6"; break; + case 14: context.fillStyle = "#cc00ff"; break; + case 15: context.fillStyle = "#ff00e5"; break; + case 16: context.fillStyle = "#ff0098"; break; + } } - else if(!isOccupied(-1, 0) && !isOccupied(1, 0)){ - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.9, r*tileSize-tileSize*0); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize); - context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); - context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.8, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); - context.bezierCurveTo((c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.4, (c+1)*tileSize+tileSize*.3, r*tileSize+tileSize*.3, (c+1)*tileSize, r*tileSize+tileSize*.02); - context.closePath(); + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + var complementPixels = (1 - 2 * outlineThickness) * tileSize; + + if (curlyOutline && !isOccupied(0, -1)) { + if (!isOccupied(-1, 0) && isOccupied(1, 0)) { + context.beginPath(); + context.moveTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .05, r * tileSize + tileSize * .3, c * tileSize + tileSize * .3, r * tileSize + tileSize * .4, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .35, r * tileSize + tileSize * .4, c * tileSize + tileSize * .6, r * tileSize + tileSize * .4, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .75, r * tileSize + tileSize * .3, c * tileSize + tileSize * .9, r * tileSize + tileSize * .4, c * tileSize + tileSize * 1, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize, r * tileSize); + context.lineTo(c * tileSize + tileSize * .2, r * tileSize); + context.bezierCurveTo(c * tileSize - tileSize * .2, r * tileSize - tileSize * .05, c * tileSize - tileSize * .15, r * tileSize + tileSize * .5, c * tileSize + tileSize * .1, r * tileSize + tileSize * .25); + context.closePath(); + } + else if (isOccupied(-1, 0) && !isOccupied(1, 0)) { + context.beginPath(); + context.moveTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .95, r * tileSize + tileSize * .3, c * tileSize + tileSize * .7, r * tileSize + tileSize * .4, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .65, r * tileSize + tileSize * .4, c * tileSize + tileSize * .4, r * tileSize + tileSize * .4, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .3, c * tileSize + tileSize * .1, r * tileSize + tileSize * .4, c * tileSize, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize, r * tileSize); + context.lineTo(c * tileSize + tileSize * .8, r * tileSize); + context.bezierCurveTo((c + 1) * tileSize + tileSize * .2, r * tileSize - tileSize * .05, (c + 1) * tileSize + tileSize * .15, r * tileSize + tileSize * .5, (c + 1) * tileSize - tileSize * .1, r * tileSize + tileSize * .25); + context.closePath(); + } + else if (!isOccupied(-1, 0) && !isOccupied(1, 0)) { + context.beginPath(); + context.moveTo(c * tileSize + tileSize * .9, r * tileSize - tileSize * 0); + context.lineTo(c * tileSize + tileSize * .2, r * tileSize); + context.bezierCurveTo(c * tileSize - tileSize * .2, r * tileSize - tileSize * .05, c * tileSize - tileSize * .15, r * tileSize + tileSize * .5, c * tileSize + tileSize * .1, r * tileSize + tileSize * .25); + context.bezierCurveTo(c * tileSize + tileSize * .05, r * tileSize + tileSize * .3, c * tileSize + tileSize * .3, r * tileSize + tileSize * .4, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .35, r * tileSize + tileSize * .4, c * tileSize + tileSize * .6, r * tileSize + tileSize * .4, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .75, r * tileSize + tileSize * .3, c * tileSize + tileSize * .8, r * tileSize + tileSize * .4, c * tileSize + tileSize * .9, r * tileSize + tileSize * .2); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .1, r * tileSize + tileSize * .4, (c + 1) * tileSize + tileSize * .3, r * tileSize + tileSize * .3, (c + 1) * tileSize, r * tileSize + tileSize * .02); + context.closePath(); + } + else { + context.beginPath(); + context.moveTo(c * tileSize, r * tileSize); + context.lineTo(c * tileSize, r * tileSize + tileSize * .15); + context.bezierCurveTo(c * tileSize + tileSize * 0, r * tileSize + tileSize * .4, c * tileSize + tileSize * .3, r * tileSize + tileSize * .3, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .35, r * tileSize + tileSize * .3, c * tileSize + tileSize * .6, r * tileSize + tileSize * .3, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .75, r * tileSize + tileSize * .4, c * tileSize + tileSize * .9, r * tileSize + tileSize * .3, c * tileSize + tileSize * 1, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize, r * tileSize); + context.closePath(); + } + context.fill(); } - else{ - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize+tileSize*.15); - context.bezierCurveTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.4, c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.3, c*tileSize+tileSize*.6, r*tileSize+tileSize*.3, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize, r*tileSize); - context.closePath(); + else if (!curlyOutline && !isOccupied(0, -1)) { + context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + } - context.fill(); + if (!curlyOutline && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(1, -1)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(1, 1)) context.fillRect((c + complement) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(0, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, tileSize, outlinePixels); + if (!curlyOutline && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!curlyOutline && !isOccupied(1, 0)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); } - else if(!curlyOutline && !isOccupied(0, -1)){ context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - - } - if (!curlyOutline && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (!curlyOutline && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!curlyOutline && !isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); - } - - function drawBushes(r, c, isOccupied){ - if(!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)){ + + function drawBushes(r, c, isOccupied) { + if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)) { /*context.shadowColor = "#666"; context.shadowOffsetX = -.5; context.shadowOffsetY = -.5; context.shadowBlur = 1;*/ - + context.beginPath(); - context.moveTo((c+1)*tileSize, r*tileSize); - context.lineTo((c+1)*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); - context.lineTo((c+1)*tileSize, r*tileSize); + context.moveTo((c + 1) * tileSize, r * tileSize); + context.lineTo((c + 1) * tileSize, r * tileSize - tileSize * .4); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .1, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .2); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .3, r * tileSize - tileSize * .2, (c + 1) * tileSize - tileSize * .4, r * tileSize - tileSize * .1, (c + 1) * tileSize - tileSize * .3, r * tileSize); + context.lineTo((c + 1) * tileSize, r * tileSize); context.closePath(); context.fill(); - + context.beginPath(); - context.moveTo((c+1)*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); + context.moveTo((c + 1) * tileSize, r * tileSize - tileSize * .4); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .1, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .2); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .3, r * tileSize - tileSize * .2, (c + 1) * tileSize - tileSize * .4, r * tileSize - tileSize * .1, (c + 1) * tileSize - tileSize * .3, r * tileSize); } - - if(!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)){ + + if (!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)) { /*context.shadowColor = "#666"; context.shadowOffsetX = .5; context.shadowOffsetY = -.5; context.shadowBlur = 1;*/ - + context.beginPath(); - context.moveTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); - context.lineTo(c*tileSize, r*tileSize); + context.moveTo(c * tileSize, r * tileSize); + context.lineTo(c * tileSize, r * tileSize - tileSize * .4); + context.bezierCurveTo(c * tileSize + tileSize * .1, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .3, r * tileSize - tileSize * .2, c * tileSize + tileSize * .4, r * tileSize - tileSize * .1, c * tileSize + tileSize * .3, r * tileSize); + context.lineTo(c * tileSize, r * tileSize); context.closePath(); context.fill(); - + context.restore(); - + context.beginPath(); - context.moveTo(c*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); + context.moveTo(c * tileSize, r * tileSize - tileSize * .4); + context.bezierCurveTo(c * tileSize + tileSize * .1, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .3, r * tileSize - tileSize * .2, c * tileSize + tileSize * .4, r * tileSize - tileSize * .1, c * tileSize + tileSize * .3, r * tileSize); /*context.strokeStyle = "#7dff1a"; - context.stroke();*/ + context.stroke();*/ } } - - function drawSpikes(r, c, adjacentTiles) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = spikeColors[0]; - - context.beginPath(); - context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes - context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.45, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.55, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.75, y + tileSize * 0.3); - - context.moveTo(x + tileSize * 0.7, y + tileSize * 0.25); //right spikes - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.45); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.55); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.75); - - context.moveTo(x + tileSize * 0.75, y + tileSize * 0.7); //bottom spikes - context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.55, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.45, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.25, y + tileSize * 0.7); - - context.moveTo(x + tileSize * 0.3, y + tileSize * 0.75); //left spikes - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.55); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.45); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); - context.closePath(); - - /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ - context.fill(); - drawSpikeSupports(r, c, isSpike, isWall); - - function isSpike(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === SPIKE; - } - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; + + function drawSpikes(r, c, adjacentTiles) { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = spikeColors[0]; + + context.beginPath(); + context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes + context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.45, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.55, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.75, y + tileSize * 0.3); + + context.moveTo(x + tileSize * 0.7, y + tileSize * 0.25); //right spikes + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.45); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.55); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.75); + + context.moveTo(x + tileSize * 0.75, y + tileSize * 0.7); //bottom spikes + context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.55, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.45, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.25, y + tileSize * 0.7); + + context.moveTo(x + tileSize * 0.3, y + tileSize * 0.75); //left spikes + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.55); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.45); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); + context.closePath(); + + /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ + context.fill(); + drawSpikeSupports(r, c, isSpike, isWall); + + function isSpike(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === SPIKE; + } + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } } - } - - function drawSpikeSupports(r, c, isOccupied, canConnect){ + + function drawSpikeSupports(r, c, isOccupied, canConnect) { var boltBool = false; var occupiedCount = 0; - if(canConnect(0, 1)){ + if (canConnect(0, 1)) { context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize+(tileSize*.3), r*tileSize+(tileSize*.8), tileSize*.4, tileSize*.4); + context.fillRect(c * tileSize + (tileSize * .3), r * tileSize + (tileSize * .8), tileSize * .4, tileSize * .4); boltBool = true; } - if(canConnect(0, -1) && !canConnect(0, 1)){ - if(!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(1, -1)){} - else{ + if (canConnect(0, -1) && !canConnect(0, 1)) { + if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(1, -1)) { } + else { context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize+(tileSize*.3), r*tileSize, tileSize*.4, tileSize*.4); + context.fillRect(c * tileSize + (tileSize * .3), r * tileSize, tileSize * .4, tileSize * .4); boltBool = true; } } - if(canConnect(-1, 0) && !canConnect(0, 1)){ - if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(-1, 1)){} - else{ + if (canConnect(-1, 0) && !canConnect(0, 1)) { + if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(-1, 1)) { } + else { context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize, r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); + context.fillRect(c * tileSize, r * tileSize + (tileSize * .3), tileSize * .4, tileSize * .4); boltBool = true; } } - if(canConnect(1, 0) && !canConnect(0, 1)){ - if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(1, -1) && canConnect(1, 1)){} - else{ + if (canConnect(1, 0) && !canConnect(0, 1)) { + if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(1, -1) && canConnect(1, 1)) { } + else { context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize+(tileSize*.8), r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); + context.fillRect(c * tileSize + (tileSize * .8), r * tileSize + (tileSize * .3), tileSize * .4, tileSize * .4); boltBool = true; } } - + context.fillStyle = spikeColors[2]; - if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING ONE - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4,br:4}, true, false); + if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING ONE + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, { bl: 4, br: 4 }, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize, tileSize*.6, {tl:4,bl:4}, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize, tileSize * .6, { tl: 4, bl: 4 }, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4,tr:4}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, { tl: 4, tr: 4 }, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4,br:4}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { tr: 4, br: 4 }, true, false); boltBool = true; } - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (CORNERS) - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {bl:4}, true, false); - if(!canConnect(1, -1)) boltBool = true; + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING TWO (CORNERS) + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, { bl: 4 }, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { bl: 4 }, true, false); + if (!canConnect(1, -1)) boltBool = true; + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { br: 4 }, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, { br: 4 }, true, false); + if (!canConnect(-1, -1)) boltBool = true; + } + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { tl: 4 }, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, { tl: 4 }, true, false); + if (!canConnect(1, 1)) boltBool = true; + } + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { tr: 4 }, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, { tr: 4 }, true, false); + if (!canConnect(-1, 1)) boltBool = true; } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {br:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {br:4}, true, false); - if(!canConnect(-1, -1)) boltBool = true; + else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING TWO (OPPOSITES) + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tl:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4}, true, false); - if(!canConnect(1, 1)) boltBool = true; - } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tr:4}, true, false); - if(!canConnect(-1, 1)) boltBool = true; - } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (OPPOSITES) - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING THREE + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, 0, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, 0, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, 0, true, false); + boltBool = true; } - else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING THREE - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, 0, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ //TOUCHING FOUR - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { //TOUCHING FOUR + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); //boltBool = true; } - else{ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.6, 0, true, false); + else { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .6, 0, true, false); boltBool = true; } - + if (boltBool) drawBolt(r, c); } - - function drawBolt(r, c){ + + function drawBolt(r, c) { context.strokeStyle = spikeColors[3]; context.beginPath(); - context.arc(c*tileSize+(tileSize*.55), r*tileSize+(tileSize*.45), 4, -.7*Math.PI, .2*Math.PI); - context.lineTo(c*tileSize+(tileSize*.45),r*tileSize+(tileSize*.35)); + context.arc(c * tileSize + (tileSize * .55), r * tileSize + (tileSize * .45), 4, -.7 * Math.PI, .2 * Math.PI); + context.lineTo(c * tileSize + (tileSize * .45), r * tileSize + (tileSize * .35)); context.closePath(); context.fillStyle = spikeColors[3]; context.fill(); context.stroke(); - + context.beginPath(); - context.moveTo(c*tileSize+(tileSize*.43),r*tileSize+(tileSize*.47)); - context.arc(c*tileSize+(tileSize*.48), r*tileSize+(tileSize*.52), 4, .2*Math.PI, -.75*Math.PI); + context.moveTo(c * tileSize + (tileSize * .43), r * tileSize + (tileSize * .47)); + context.arc(c * tileSize + (tileSize * .48), r * tileSize + (tileSize * .52), 4, .2 * Math.PI, -.75 * Math.PI); //context.lineTo(c*tileSize+(tileSize*.4),r*tileSize+(tileSize*.6)); context.closePath(); context.fillStyle = spikeColors[3]; context.fill(); context.stroke(); } - - function drawConnector(context, r1, c1, r2, c2, color) { - // either r1 and r2 or c1 and c2 must be equal - if (r1 > r2 || c1 > c2) { - var rTmp = r1; - var cTmp = c1; - r1 = r2; - c1 = c2; - r2 = rTmp; - c2 = cTmp; - } - var xLo = (c1 + 0.3) * tileSize; - var yLo = (r1 + 0.3) * tileSize; - var xHi = (c2 + 0.45) * tileSize; - var yHi = (r2 + 0.45) * tileSize; - context.fillStyle = color; - context.fillRect(xLo+.15*tileSize, yLo+.15*tileSize, xHi - xLo, yHi - yLo); - } - function drawBlock(block) { - var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); - var rowcols = block.locations.map(function(location) { - return getRowcol(level, location); - }); - rowcols.forEach(function(rowcol) { - var r = rowcol.r + animationDisplacementRowcol.r; - var c = rowcol.c + animationDisplacementRowcol.c; - context.fillStyle = blockColors[0][block.id % blockColors[0].length]; - var outlineThickness = .2; - - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - if (!isAlsoThisBlock(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - if (!isAlsoThisBlock( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (!isAlsoThisBlock(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!isAlsoThisBlock( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); - - function isAlsoThisBlock(dc, dr) { - for (var i = 0; i < rowcols.length; i++) { - var otherRowcol = rowcols[i]; - if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; + + function drawConnector(context, r1, c1, r2, c2, color) { + // either r1 and r2 or c1 and c2 must be equal + if (r1 > r2 || c1 > c2) { + var rTmp = r1; + var cTmp = c1; + r1 = r2; + c1 = c2; + r2 = rTmp; + c2 = cTmp; } - return false; - } - }); - } - function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { - var cx = (c + 0.5) * tileSize; - var cy = (r + 0.5) * tileSize; - context.fillStyle = fillStyle; - context.beginPath(); - context.moveTo(cx, cy); - context.arc(cx, cy, radiusFactor * tileSize/2, quadrant * Math.PI/2, (quadrant + 1) * Math.PI/2); - context.fill(); - } - function drawDiamond(r, c, fillStyle) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = fillStyle; - roundRect(context, x, y, tileSize, tileSize, 10, true, false); - } - function drawCircle(r, c, radiusFactor, fillStyle) { - context.fillStyle = fillStyle; - context.beginPath(); - context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize/2 * radiusFactor, 0, 2*Math.PI); - context.fill(); - } - function drawRect(r, c, fillStyle) { - context.fillStyle = fillStyle; - context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); - } - - function drawCloud(c, x, y){ + var xLo = (c1 + 0.3) * tileSize; + var yLo = (r1 + 0.3) * tileSize; + var xHi = (c2 + 0.45) * tileSize; + var yHi = (r2 + 0.45) * tileSize; + context.fillStyle = color; + context.fillRect(xLo + .15 * tileSize, yLo + .15 * tileSize, xHi - xLo, yHi - yLo); + } + function drawBlock(block) { + var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); + var rowcols = block.locations.map(function (location) { + return getRowcol(level, location); + }); + rowcols.forEach(function (rowcol) { + var r = rowcol.r + animationDisplacementRowcol.r; + var c = rowcol.c + animationDisplacementRowcol.c; + context.fillStyle = blockColors[block.id % blockColors.length]; + var outlineThickness = .2; + + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + if (!isAlsoThisBlock(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(1, -1)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(-1, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(1, 1)) context.fillRect((c + complement) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + if (!isAlsoThisBlock(0, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, tileSize, outlinePixels); + if (!isAlsoThisBlock(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!isAlsoThisBlock(1, 0)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); + + function isAlsoThisBlock(dc, dr) { + for (var i = 0; i < rowcols.length; i++) { + var otherRowcol = rowcols[i]; + if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; + } + return false; + } + }); + } + function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { + var cx = (c + 0.5) * tileSize; + var cy = (r + 0.5) * tileSize; + context.fillStyle = fillStyle; + context.beginPath(); + context.moveTo(cx, cy); + context.arc(cx, cy, radiusFactor * tileSize / 2, quadrant * Math.PI / 2, (quadrant + 1) * Math.PI / 2); + context.fill(); + } + function drawDiamond(r, c, fillStyle) { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = fillStyle; + roundRect(context, x, y, tileSize, tileSize, 10, true, false); + } + function drawCircle(r, c, radiusFactor, fillStyle) { + context.fillStyle = fillStyle; + context.beginPath(); + context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize / 2 * radiusFactor, 0, 2 * Math.PI); + context.fill(); + } + function drawRect(r, c, fillStyle) { + context.fillStyle = fillStyle; + context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); + } + + function drawCloud(c, x, y) { c.fillStyle = experimentalColors[0]; /*c.beginPath(); c.rect(x, y, tileSize, tileSize); c.fill(); c.closePath();*/ - + c.beginPath(); - c.moveTo(x+tileSize*0, y+tileSize*0); - - c.bezierCurveTo(x+tileSize*0, y-tileSize*.15, x+tileSize*.33, y-tileSize*.15, x+tileSize*.33, y+tileSize*0); - c.bezierCurveTo(x+tileSize*.33, y-tileSize*.15, x+tileSize*.67, y-tileSize*.15, x+tileSize*.67, y+tileSize*0); - c.bezierCurveTo(x+tileSize*.67, y-tileSize*.15, x+tileSize*1, y-tileSize*.15, x+tileSize*1, y+tileSize*0); - - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*0, x+tileSize*1.15, y+tileSize*.33, x+tileSize*1, y+tileSize*.33); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.33, x+tileSize*1.15, y+tileSize*.67, x+tileSize*1, y+tileSize*.67); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.67, x+tileSize*1.15, y+tileSize*1, x+tileSize*1, y+tileSize*1); - - c.bezierCurveTo(x+tileSize*1, y+tileSize*1.15, x+tileSize*.67, y+tileSize*1.15, x+tileSize*.67, y+tileSize*1); - c.bezierCurveTo(x+tileSize*.67, y+tileSize*1.15, x+tileSize*.33, y+tileSize*1.15, x+tileSize*.33, y+tileSize*1); - c.bezierCurveTo(x+tileSize*.33, y+tileSize*1.15, x+tileSize*0, y+tileSize*1.15, x+tileSize*0, y+tileSize*1); - - c.bezierCurveTo(x-tileSize*.15, y+tileSize*1, x-tileSize*.15, y+tileSize*.67, x+tileSize*0, y+tileSize*.67); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*.67, x-tileSize*.15, y+tileSize*.33, x+tileSize*0, y+tileSize*.33); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*.33, x-tileSize*.15, y+tileSize*0, x+tileSize*0, y+tileSize*0); - + c.moveTo(x + tileSize * 0, y + tileSize * 0); + + c.bezierCurveTo(x + tileSize * 0, y - tileSize * .15, x + tileSize * .33, y - tileSize * .15, x + tileSize * .33, y + tileSize * 0); + c.bezierCurveTo(x + tileSize * .33, y - tileSize * .15, x + tileSize * .67, y - tileSize * .15, x + tileSize * .67, y + tileSize * 0); + c.bezierCurveTo(x + tileSize * .67, y - tileSize * .15, x + tileSize * 1, y - tileSize * .15, x + tileSize * 1, y + tileSize * 0); + + c.bezierCurveTo(x + tileSize * 1.15, y + tileSize * 0, x + tileSize * 1.15, y + tileSize * .33, x + tileSize * 1, y + tileSize * .33); + c.bezierCurveTo(x + tileSize * 1.15, y + tileSize * .33, x + tileSize * 1.15, y + tileSize * .67, x + tileSize * 1, y + tileSize * .67); + c.bezierCurveTo(x + tileSize * 1.15, y + tileSize * .67, x + tileSize * 1.15, y + tileSize * 1, x + tileSize * 1, y + tileSize * 1); + + c.bezierCurveTo(x + tileSize * 1, y + tileSize * 1.15, x + tileSize * .67, y + tileSize * 1.15, x + tileSize * .67, y + tileSize * 1); + c.bezierCurveTo(x + tileSize * .67, y + tileSize * 1.15, x + tileSize * .33, y + tileSize * 1.15, x + tileSize * .33, y + tileSize * 1); + c.bezierCurveTo(x + tileSize * .33, y + tileSize * 1.15, x + tileSize * 0, y + tileSize * 1.15, x + tileSize * 0, y + tileSize * 1); + + c.bezierCurveTo(x - tileSize * .15, y + tileSize * 1, x - tileSize * .15, y + tileSize * .67, x + tileSize * 0, y + tileSize * .67); + c.bezierCurveTo(x - tileSize * .15, y + tileSize * .67, x - tileSize * .15, y + tileSize * .33, x + tileSize * 0, y + tileSize * .33); + c.bezierCurveTo(x - tileSize * .15, y + tileSize * .33, x - tileSize * .15, y + tileSize * 0, x + tileSize * 0, y + tileSize * 0); + c.closePath(); c.fill(); //c.stroke(); } -function drawFace(snake, headCol, headRow, orientation){ - var x = headCol * tileSize; - var y = headRow * tileSize; - - var scaleFactor = 1.5; - var scale1; - var scale2; - var eye1 = tileSize*.8; - var eye2 = tileSize*.4; - - var eyeSize = tileSize/5; - var eyeRotation = 2; - var z1, z2, z3, z4, z5, z6, z7, z8; - var a1, a2, a3, a4, a5, a6, a7, a8; - var beakRotation = 1.5; - var arcDirection = false; - - switch(orientation){ - case 0: //red up and blue left - z1 = eye2; - z2 = tileSize-eye1; - z3 = eye2; - z4 = tileSize-eye2; - z5 = eye2; - z6 = tileSize-eye1; - z7 = eye2; - z8 = tileSize-eye2 - eyeRotation = 1.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize*.7; - a2 = tileSize-tileSize*.7; - a3 = tileSize*.7; - a4 = -tileSize*.3; - a5 = tileSize*.7; - a6 = tileSize*.3; - a7 = tileSize/6; - a8 = 0; - beakRotation = 1; - arcDirection = false; - break; - case 1: //red right and blue up - z1 = eye1; - z2 = eye2; - z3 = eye2; - z4 = eye2; - z5 = eye1; - z6 = eye2; - z7 = eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize*1.3; - a4 = tileSize*.7; - a5 = tileSize*.7; - a6 = tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = false; - break; - case 2: //red down and blue right - z1 = tileSize-eye2; - z2 = eye1; - z3 = tileSize-eye2; - z4 = eye2; - z5 = tileSize-eye2; - z6 = eye1; - z7 = tileSize-eye2; - z8 = eye2; - eyeRotation = 2.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize-tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize-tileSize*.7; - a4 = tileSize*1.3; - a5 = tileSize-tileSize*.7; - a6 = tileSize*.7; - a7 = tileSize/6; - a8 = 0; - beakRotation = 1; - arcDirection = true; - break; - case 3: //red left and blue down - z1 = tileSize-eye1; - z2 = tileSize-eye2; - z3 = tileSize-eye2; - z4 = tileSize-eye2; - z5 = tileSize-eye1; - z6 = tileSize-eye2; - z7 = tileSize-eye2; - z8 = tileSize-eye2; - eyeRotation = 3; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize-tileSize*.7; - a2 = tileSize-tileSize*.7; - a3 = tileSize-tileSize*1.3; - a4 = tileSize-tileSize*.7; - a5 = tileSize-tileSize*.7; - a6 = tileSize-tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = true; - break; - case 4: //green up and yellow right - z1 = tileSize-eye2; - z2 = tileSize-eye1; - z3 = tileSize-eye2; - z4 = tileSize-eye2; - z5 = tileSize-eye2; - z6 = tileSize-eye1; - z7 = tileSize-eye2; - z8 = tileSize-eye2 - eyeRotation = 2.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize-tileSize*.7; - a2 = tileSize-tileSize*.7; - a3 = tileSize-tileSize*.7; - a4 = -tileSize*.3; - a5 = tileSize-tileSize*.7; - a6 = tileSize*.3; - a7 = tileSize/6; - a8 = 0; - beakRotation = 1; - arcDirection = false; - break; - case 5: //green right and yellow down - z1 = eye1; - z2 = tileSize-eye2; - z3 = eye2; - z4 = tileSize-eye2; - z5 = eye1; - z6 = tileSize-eye2; - z7 = eye2; - z8 = tileSize-eye2; - eyeRotation = 3; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize*.7; - a2 = tileSize-tileSize*.7; - a3 = tileSize*1.3; - a4 = tileSize-tileSize*.7; - a5 = tileSize*.7; - a6 = tileSize-tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = false; - break; - case 6: //green down and yellow left - z1 = eye2; - z2 = eye1; - z3 = eye2; - z4 = eye2; - z5 = eye2; - z6 = eye1; - z7 = eye2; - z8 = eye2; - eyeRotation = 1.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize*.7; - a4 = tileSize*1.3; - a5 = tileSize*.7; - a6 = tileSize*.7; - a7 = tileSize/6; - a8 = 0; - beakRotation = 1; - arcDirection = true; - break; - case 7: //green left and yellow up - z1 = tileSize-eye1; - z2 = eye2; - z3 = tileSize-eye2; - z4 = eye2; - z5 = tileSize-eye1; - z6 = eye2; - z7 = tileSize-eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize-tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize-tileSize*1.3; - a4 = tileSize*.7; - a5 = tileSize-tileSize*.7; - a6 = tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = true; - break; - case 10: //single unit snake - z1 = eye1; - z2 = eye2; - z3 = eye2; - z4 = eye2; - z5 = eye1; - z6 = eye2; - z7 = eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize*1.3; - a4 = tileSize*.7; - a5 = tileSize*.7; - a6 = tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = false; - break; - } - - if (snake === activeSnakeId) { //draw eyes for active snake only - context.fillStyle = "white"; - context.save(); - context.scale(scale1,scale2); - context.beginPath(); - context.arc((x+z1)/scale1, (y+z2)/scale2, eyeSize, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); + function drawFace(snake, headCol, headRow, orientation) { + var x = headCol * tileSize; + var y = headRow * tileSize; + + var scaleFactor = 1.5; + var scale1; + var scale2; + var eye1 = tileSize * .8; + var eye2 = tileSize * .4; + + var eyeSize = tileSize / 5; + var eyeRotation = 2; + var z1, z2, z3, z4, z5, z6, z7, z8; + var a1, a2, a3, a4, a5, a6, a7, a8; + var beakRotation = 1.5; + var arcDirection = false; + + switch (orientation) { + case 0: //red up and blue left + z1 = eye2; + z2 = tileSize - eye1; + z3 = eye2; + z4 = tileSize - eye2; + z5 = eye2; + z6 = tileSize - eye1; + z7 = eye2; + z8 = tileSize - eye2 + eyeRotation = 1.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize * .7; + a2 = tileSize - tileSize * .7; + a3 = tileSize * .7; + a4 = -tileSize * .3; + a5 = tileSize * .7; + a6 = tileSize * .3; + a7 = tileSize / 6; + a8 = 0; + beakRotation = 1; + arcDirection = false; + break; + case 1: //red right and blue up + z1 = eye1; + z2 = eye2; + z3 = eye2; + z4 = eye2; + z5 = eye1; + z6 = eye2; + z7 = eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize * 1.3; + a4 = tileSize * .7; + a5 = tileSize * .7; + a6 = tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = false; + break; + case 2: //red down and blue right + z1 = tileSize - eye2; + z2 = eye1; + z3 = tileSize - eye2; + z4 = eye2; + z5 = tileSize - eye2; + z6 = eye1; + z7 = tileSize - eye2; + z8 = eye2; + eyeRotation = 2.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize - tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize - tileSize * .7; + a4 = tileSize * 1.3; + a5 = tileSize - tileSize * .7; + a6 = tileSize * .7; + a7 = tileSize / 6; + a8 = 0; + beakRotation = 1; + arcDirection = true; + break; + case 3: //red left and blue down + z1 = tileSize - eye1; + z2 = tileSize - eye2; + z3 = tileSize - eye2; + z4 = tileSize - eye2; + z5 = tileSize - eye1; + z6 = tileSize - eye2; + z7 = tileSize - eye2; + z8 = tileSize - eye2; + eyeRotation = 3; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize - tileSize * .7; + a2 = tileSize - tileSize * .7; + a3 = tileSize - tileSize * 1.3; + a4 = tileSize - tileSize * .7; + a5 = tileSize - tileSize * .7; + a6 = tileSize - tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = true; + break; + case 4: //green up and yellow right + z1 = tileSize - eye2; + z2 = tileSize - eye1; + z3 = tileSize - eye2; + z4 = tileSize - eye2; + z5 = tileSize - eye2; + z6 = tileSize - eye1; + z7 = tileSize - eye2; + z8 = tileSize - eye2 + eyeRotation = 2.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize - tileSize * .7; + a2 = tileSize - tileSize * .7; + a3 = tileSize - tileSize * .7; + a4 = -tileSize * .3; + a5 = tileSize - tileSize * .7; + a6 = tileSize * .3; + a7 = tileSize / 6; + a8 = 0; + beakRotation = 1; + arcDirection = false; + break; + case 5: //green right and yellow down + z1 = eye1; + z2 = tileSize - eye2; + z3 = eye2; + z4 = tileSize - eye2; + z5 = eye1; + z6 = tileSize - eye2; + z7 = eye2; + z8 = tileSize - eye2; + eyeRotation = 3; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize * .7; + a2 = tileSize - tileSize * .7; + a3 = tileSize * 1.3; + a4 = tileSize - tileSize * .7; + a5 = tileSize * .7; + a6 = tileSize - tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = false; + break; + case 6: //green down and yellow left + z1 = eye2; + z2 = eye1; + z3 = eye2; + z4 = eye2; + z5 = eye2; + z6 = eye1; + z7 = eye2; + z8 = eye2; + eyeRotation = 1.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize * .7; + a4 = tileSize * 1.3; + a5 = tileSize * .7; + a6 = tileSize * .7; + a7 = tileSize / 6; + a8 = 0; + beakRotation = 1; + arcDirection = true; + break; + case 7: //green left and yellow up + z1 = tileSize - eye1; + z2 = eye2; + z3 = tileSize - eye2; + z4 = eye2; + z5 = tileSize - eye1; + z6 = eye2; + z7 = tileSize - eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize - tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize - tileSize * 1.3; + a4 = tileSize * .7; + a5 = tileSize - tileSize * .7; + a6 = tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = true; + break; + case 10: //single unit snake + z1 = eye1; + z2 = eye2; + z3 = eye2; + z4 = eye2; + z5 = eye1; + z6 = eye2; + z7 = eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize * 1.3; + a4 = tileSize * .7; + a5 = tileSize * .7; + a6 = tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = false; + break; + } - context.fillStyle = "white"; - context.save(); - context.scale(scale1,scale2); - context.beginPath(); - context.arc((x+z3)/scale1, (y+z4)/scale2, eyeSize, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); + if (snake === activeSnakeId) { //draw eyes for active snake only + context.fillStyle = "white"; + context.save(); + context.scale(scale1, scale2); + context.beginPath(); + context.arc((x + z1) / scale1, (y + z2) / scale2, eyeSize, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); - context.fillStyle = "black"; - context.save(); - context.scale(scale1,scale2); - context.beginPath(); - context.arc((x+z5)/scale1, (y+z6)/scale2, eyeSize/2, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); + context.fillStyle = "white"; + context.save(); + context.scale(scale1, scale2); + context.beginPath(); + context.arc((x + z3) / scale1, (y + z4) / scale2, eyeSize, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); - context.fillStyle = "black"; - context.save(); - context.scale(scale1,scale2); + context.fillStyle = "black"; + context.save(); + context.scale(scale1, scale2); + context.beginPath(); + context.arc((x + z5) / scale1, (y + z6) / scale2, eyeSize / 2, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + + context.fillStyle = "black"; + context.save(); + context.scale(scale1, scale2); + context.beginPath(); + context.arc((x + z7) / scale1, (y + z8) / scale2, eyeSize / 2, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + } + + //beak + context.fillStyle = "#F9921C"; context.beginPath(); - context.arc((x+z7)/scale1, (y+z8)/scale2, eyeSize/2, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.arc(x + a1, y + a2, tileSize / 6, (beakRotation - 1) * Math.PI, beakRotation * Math.PI, arcDirection); + context.lineTo(x + a3, y + a4); + context.lineTo(x + a5 + a7, y + a6 + a8); context.closePath(); - context.restore(); context.fill(); } - - //beak - context.fillStyle = "#F9921C"; - context.beginPath(); - context.arc(x+a1, y+a2, tileSize/6, (beakRotation-1)*Math.PI, beakRotation*Math.PI, arcDirection); - context.lineTo(x+a3, y+a4); - context.lineTo(x+a5+a7, y+a6+a8); - context.closePath(); - context.fill(); -} - - function roundRect(ctx, x, y, width, height, radius, fill, stroke) { //Gooby - if (typeof stroke === 'undefined') { - stroke = true; - } - if (typeof radius === 'undefined') { - radius = 5; - } - if (typeof radius === 'number') { - radius = {tl: radius, tr: radius, br: radius, bl: radius}; - } else { - var defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0}; - for (var side in defaultRadius) { - radius[side] = radius[side] || defaultRadius[side]; + + function roundRect(ctx, x, y, width, height, radius, fill, stroke) { + if (typeof stroke === 'undefined') { + stroke = true; + } + if (typeof radius === 'undefined') { + radius = 5; + } + if (typeof radius === 'number') { + radius = { tl: radius, tr: radius, br: radius, bl: radius }; + } else { + var defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 }; + for (var side in defaultRadius) { + radius[side] = radius[side] || defaultRadius[side]; + } + } + ctx.beginPath(); + ctx.moveTo(x + radius.tl, y); + ctx.lineTo(x + width - radius.tr, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); + ctx.lineTo(x + width, y + height - radius.br); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); + ctx.lineTo(x + radius.bl, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl); + ctx.lineTo(x, y + radius.tl); + ctx.quadraticCurveTo(x, y, x + radius.tl, y); + ctx.closePath(); + if (fill) { + ctx.fill(); + } + if (stroke) { + ctx.stroke(); } - } - ctx.beginPath(); - ctx.moveTo(x + radius.tl, y); - ctx.lineTo(x + width - radius.tr, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); - ctx.lineTo(x + width, y + height - radius.br); - ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); - ctx.lineTo(x + radius.bl, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl); - ctx.lineTo(x, y + radius.tl); - ctx.quadraticCurveTo(x, y, x + radius.tl, y); - ctx.closePath(); - if (fill) { - ctx.fill(); - } - if (stroke) { - ctx.stroke(); - } } - -function shadeColor(color, percent) { - var R = parseInt(color.substring(1,3),16); - var G = parseInt(color.substring(3,5),16); - var B = parseInt(color.substring(5,7),16); + function shadeColor(color, percent) { - R = parseInt(R * (100 + percent) / 100); - G = parseInt(G * (100 + percent) / 100); - B = parseInt(B * (100 + percent) / 100); + var R = parseInt(color.substring(1, 3), 16); + var G = parseInt(color.substring(3, 5), 16); + var B = parseInt(color.substring(5, 7), 16); - R = (R<255)?R:255; - G = (G<255)?G:255; - B = (B<255)?B:255; + R = parseInt(R * (100 + percent) / 100); + G = parseInt(G * (100 + percent) / 100); + B = parseInt(B * (100 + percent) / 100); - var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16)); - var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16)); - var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16)); + R = (R < 255) ? R : 255; + G = (G < 255) ? G : 255; + B = (B < 255) ? B : 255; - return "#"+RR+GG+BB; -} + var RR = ((R.toString(16).length == 1) ? "0" + R.toString(16) : R.toString(16)); + var GG = ((G.toString(16).length == 1) ? "0" + G.toString(16) : G.toString(16)); + var BB = ((B.toString(16).length == 1) ? "0" + B.toString(16) : B.toString(16)); + + return "#" + RR + GG + BB; + } - - function drawR(r,c,fillStyle){ //Gooby + + function drawR(r, c, fillStyle) { context.fillStyle = fillStyle; var cornerRadius = 20; context.lineJoin = "round"; context.lineWidth = 1; - context.strokeRect(c*tileSize, r*tileSize, tileSize, tileSize); + context.strokeRect(c * tileSize, r * tileSize, tileSize, tileSize); //context.fillRect(c*tileSize, r*tileSize, tileSize, tileSize); } - function drawGrid() { - var buffer = document.createElement("canvas"); - buffer.width = canvas.width; - buffer.height = canvas.height; - var localContext = buffer.getContext("2d"); + function drawGrid() { + var buffer = document.createElement("canvas"); + buffer.width = canvas.width; + buffer.height = canvas.height; + var localContext = buffer.getContext("2d"); + + localContext.strokeStyle = "#fff"; + localContext.beginPath(); + for (var r = 0; r < level.height; r++) { + localContext.moveTo(0, tileSize * r); + localContext.lineTo(tileSize * level.width, tileSize * r); + } + for (var c = 0; c < level.width; c++) { + localContext.moveTo(tileSize * c, 0); + localContext.lineTo(tileSize * c, tileSize * level.height); + } + localContext.stroke(); - localContext.strokeStyle = "#fff"; - localContext.beginPath(); - for (var r = 0; r < level.height; r++) { - localContext.moveTo(0, tileSize*r); - localContext.lineTo(tileSize*level.width, tileSize*r); - } - for (var c = 0; c < level.width; c++) { - localContext.moveTo(tileSize*c, 0); - localContext.lineTo(tileSize*c, tileSize*level.height); + context.save(); + context.globalAlpha = 0.4; + context.drawImage(buffer, 0, 0); + context.restore(); } - localContext.stroke(); - - context.save(); - context.globalAlpha = 0.4; - context.drawImage(buffer, 0, 0); - context.restore(); - } } function findAnimation(animationTypes, objectId) { - if (animationQueueCursor === animationQueue.length) return null; - var currentAnimation = animationQueue[animationQueueCursor]; - for (var i = 1; i < currentAnimation.length; i++) { - var animation = currentAnimation[i]; - if (animationTypes.indexOf(animation[0]) !== -1 && animation[1] === objectId) return animation; - } + if (animationQueueCursor === animationQueue.length) return null; + var currentAnimation = animationQueue[animationQueueCursor]; + for (var i = 1; i < currentAnimation.length; i++) { + var animation = currentAnimation[i]; + if (animationTypes.indexOf(animation[0]) !== -1 && animation[1] === objectId) return animation; + } } function findAnimationDisplacementRowcol(objectType, objectId) { - var dr = 0; - var dc = 0; - var animationTypes = [ - "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK - "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK - ]; - // skip the current one - for (var i = animationQueueCursor + 1; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === objectId) { - dr += animation[2]; - dc += animation[3]; - } + var dr = 0; + var dc = 0; + var animationTypes = [ + "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK + "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK + ]; + // skip the current one + for (var i = animationQueueCursor + 1; i < animationQueue.length; i++) { + var animations = animationQueue[i]; + for (var j = 1; j < animations.length; j++) { + var animation = animations[j]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === objectId) { + dr += animation[2]; + dc += animation[3]; + } + } } - } - var movementAnimation = findAnimation(animationTypes, objectId); - if (movementAnimation != null) { - dr += movementAnimation[2] * (1 - animationProgress); - dc += movementAnimation[3] * (1 - animationProgress); - } - return {r: -dr, c: -dc}; + var movementAnimation = findAnimation(animationTypes, objectId); + if (movementAnimation != null) { + dr += movementAnimation[2] * (1 - animationProgress); + dc += movementAnimation[3] * (1 - animationProgress); + } + return { r: -dr, c: -dc }; } function hasFutureRemoveAnimation(object) { - var animationTypes = [ - EXIT_SNAKE, - DIE_BLOCK, - ]; - for (var i = animationQueueCursor; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === object.id) { - return true; - } + var animationTypes = [ + EXIT_SNAKE, + DIE_BLOCK, + ]; + for (var i = animationQueueCursor; i < animationQueue.length; i++) { + var animations = animationQueue[i]; + for (var j = 1; j < animations.length; j++) { + var animation = animations[j]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === object.id) { + return true; + } + } } - } } function previewPaste(hoverR, hoverC) { - var offsetR = hoverR - clipboardOffsetRowcol.r; - var offsetC = hoverC - clipboardOffsetRowcol.c; - - var newLevel = JSON.parse(JSON.stringify(level)); - var selectedLocations = []; - var selectedObjects = []; - clipboardData.selectedLocations.forEach(function(location) { - var tileCode = clipboardData.level.map[location]; - var rowcol = getRowcol(clipboardData.level, location); - var r = rowcol.r + offsetR; - var c = rowcol.c + offsetC; - if (!isInBounds(newLevel, r, c)) return; - var newLocation = getLocation(newLevel, r, c); - newLevel.map[newLocation] = tileCode; - selectedLocations.push(newLocation); - }); - clipboardData.selectedObjects.forEach(function(object) { - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(clipboardData.level, object.locations[i]); - rowcol.r += offsetR; - rowcol.c += offsetC; - if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { - // this location is oob - if (object.type === SNAKE) { - // snakes must be completely in bounds - return; + var offsetR = hoverR - clipboardOffsetRowcol.r; + var offsetC = hoverC - clipboardOffsetRowcol.c; + + var newLevel = JSON.parse(JSON.stringify(level)); + var selectedLocations = []; + var selectedObjects = []; + clipboardData.selectedLocations.forEach(function (location) { + var tileCode = clipboardData.level.map[location]; + var rowcol = getRowcol(clipboardData.level, location); + var r = rowcol.r + offsetR; + var c = rowcol.c + offsetC; + if (!isInBounds(newLevel, r, c)) return; + var newLocation = getLocation(newLevel, r, c); + newLevel.map[newLocation] = tileCode; + selectedLocations.push(newLocation); + }); + clipboardData.selectedObjects.forEach(function (object) { + var newLocations = []; + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(clipboardData.level, object.locations[i]); + rowcol.r += offsetR; + rowcol.c += offsetC; + if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { + // this location is oob + if (object.type === SNAKE) { + // snakes must be completely in bounds + return; + } + // just skip it + continue; + } + var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); + newLocations.push(newLocation); } - // just skip it - continue; - } - var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); - newLocations.push(newLocation); - } - if (newLocations.length === 0) return; // can't have a non-present object - var newObject = JSON.parse(JSON.stringify(object)); - newObject.locations = newLocations; - selectedObjects.push(newObject); - }); - return { - level: newLevel, - selectedLocations: selectedLocations, - selectedObjects: selectedObjects, - }; + if (newLocations.length === 0) return; // can't have a non-present object + var newObject = JSON.parse(JSON.stringify(object)); + newObject.locations = newLocations; + selectedObjects.push(newObject); + }); + return { + level: newLevel, + selectedLocations: selectedLocations, + selectedObjects: selectedObjects, + }; } function getNaiveOrthogonalPath(a, b) { - // does not include a, but does include b. - var rowcolA = getRowcol(level, a); - var rowcolB = getRowcol(level, b); - var path = []; - if (rowcolA.r < rowcolB.r) { - for (var r = rowcolA.r; r < rowcolB.r; r++) { - path.push(getLocation(level, r + 1, rowcolA.c)); - } - } else { - for (var r = rowcolA.r; r > rowcolB.r; r--) { - path.push(getLocation(level, r - 1, rowcolA.c)); - } - } - if (rowcolA.c < rowcolB.c) { - for (var c = rowcolA.c; c < rowcolB.c; c++) { - path.push(getLocation(level, rowcolB.r, c + 1)); + // does not include a, but does include b. + var rowcolA = getRowcol(level, a); + var rowcolB = getRowcol(level, b); + var path = []; + if (rowcolA.r < rowcolB.r) { + for (var r = rowcolA.r; r < rowcolB.r; r++) { + path.push(getLocation(level, r + 1, rowcolA.c)); + } + } else { + for (var r = rowcolA.r; r > rowcolB.r; r--) { + path.push(getLocation(level, r - 1, rowcolA.c)); + } } - } else { - for (var c = rowcolA.c; c > rowcolB.c; c--) { - path.push(getLocation(level, rowcolB.r, c - 1)); + if (rowcolA.c < rowcolB.c) { + for (var c = rowcolA.c; c < rowcolB.c; c++) { + path.push(getLocation(level, rowcolB.r, c + 1)); + } + } else { + for (var c = rowcolA.c; c > rowcolB.c; c--) { + path.push(getLocation(level, rowcolB.r, c - 1)); + } } - } - return path; + return path; } function identityFunction(x) { - return x; + return x; } function compareId(a, b) { - return operatorCompare(a.id, b.id); + return operatorCompare(a.id, b.id); } function operatorCompare(a, b) { - return a < b ? -1 : a > b ? 1 : 0; + return a < b ? -1 : a > b ? 1 : 0; } function clamp(value, min, max) { - if (value < min) return min; - if (value > max) return max; - return value; + if (value < min) return min; + if (value > max) return max; + return value; } function copyArray(array) { - return array.map(identityFunction); + return array.map(identityFunction); } function getSetIntersection(array1, array2) { - if (array1.length * array2.length === 0) return []; - return array1.filter(function(x) { return array2.indexOf(x) !== -1; }); + if (array1.length * array2.length === 0) return []; + return array1.filter(function (x) { return array2.indexOf(x) !== -1; }); } function makeScaleCoordinatesFunction(width1, width2) { - return function(location) { - return location + (width2 - width1) * Math.floor(location / width1); - }; + return function (location) { + return location + (width2 - width1) * Math.floor(location / width1); + }; } var expectHash; -window.addEventListener("hashchange", function() { - if (location.hash === expectHash) { - // We're in the middle of saveLevel() or saveReplay(). - // Don't react to that event. - expectHash = null; - return; - } - // The user typed into the url bar or used Back/Forward browser buttons, etc. - loadFromLocationHash(); +window.addEventListener("hashchange", function () { + if (location.hash === expectHash) { + // We're in the middle of saveLevel() or saveReplay(). + // Don't react to that event. + expectHash = null; + return; + } + // The user typed into the url bar or used Back/Forward browser buttons, etc. + loadFromLocationHash(); }); function loadFromLocationHash() { - var hashSegments = location.hash.split("#"); - hashSegments.shift(); // first element is always "" - if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; - var hashPairs = hashSegments.map(function(segment) { - var equalsIndex = segment.indexOf("="); - if (equalsIndex === -1) return ["", segment]; // bad - return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; - }); - - if (hashPairs[0][0] !== "level") return false; - try { - var level = parseLevel(hashPairs[0][1]); - } catch (e) { - alert(e); - return false; - } - loadLevel(level); - if (hashPairs.length > 1) { + var hashSegments = location.hash.split("#"); + hashSegments.shift(); // first element is always "" + if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; + var hashPairs = hashSegments.map(function (segment) { + var equalsIndex = segment.indexOf("="); + if (equalsIndex === -1) return ["", segment]; // bad + return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; + }); + + if (hashPairs[0][0] !== "level") return false; try { - if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); - parseAndLoadReplay(hashPairs[1][1]); + var level = parseLevel(hashPairs[0][1]); } catch (e) { - alert(e); - return false; + alert(e); + return false; + } + loadLevel(level); + if (hashPairs.length > 1) { + try { + if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); + parseAndLoadReplay(hashPairs[1][1]); + } catch (e) { + alert(e); + return false; + } } - } - return true; + return true; } // run test suite @@ -4418,5 +4416,5 @@ testTime = new Date().getTime() - testTime; loadPersistentState(); if (!loadFromLocationHash()) { - loadLevel(parseLevel(exampleLevel)); + loadLevel(parseLevel(exampleLevel)); } From 443714d77f9bc8d44c040b48d8e2359a7b6f8766 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 24 Feb 2020 17:52:48 -0500 Subject: [PATCH 292/577] Update Main.js --- Main.js | 78 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 42 insertions(+), 36 deletions(-) diff --git a/Main.js b/Main.js index 786d6f3b..fedfadd8 100644 --- a/Main.js +++ b/Main.js @@ -1741,6 +1741,7 @@ var bg4 = "rgba(7, 7, 83 * rgba(0, 0, 70"; var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; //must be full length to satisfy tint function var snakeColors2 = ["#ff0000", "#00ff00", "#0000ff", "#ffff00"]; var snakeColors3 = ["#BA145C", "#E91624", "#F75802", "#FEFE28"]; +var snakeColors4 = ["#ffffff", "#ffffff", "#ffffff", "#ffffff"]; var fruitColors1 = ["#ff0066", "#ff36a6", "#ff6b1f", "#ff9900", "#ff2600"]; var fruitColors2 = ["black", "black", "black", "black", "black"]; @@ -1750,7 +1751,7 @@ var spikeColors2 = ["gray", "black", "white", "black"]; var spikeColors3 = ["#333", "#333", "#333", "#777"]; var blockColors1 = ["#de5a6d", "#fa65dd", "#c367e3", "#9c62fa", "#625ff0"]; //must be full length to satisfy tint function -var blockColors2 = ["#999999"]; +var blockColors2 = ["#ffffff"]; var blockColors3 = ["#de7913", "#7d46a0", "#39868b", "#41ccc2", "#ded800"]; var blockColors4 = ["#150612", "#a52e8b", "#990077", "#d917af", "#4d003c"]; @@ -1772,7 +1773,7 @@ var themes = [ //name, background, material, surface, curlyOutline, blockColors ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], - ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] + ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors4, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] ]; @@ -1814,8 +1815,9 @@ function move(dr, dc) { if (isCollision()) { var newTile = level.map[newLocation]; - if (newTile === BUBBLE || newTile === CLOUD) + if (newTile === BUBBLE || newTile === CLOUD) { paintTileAtLocation(newLocation, SPACE, changeLog); + } else if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile var otherObject = findObjectAtLocation(newLocation); if (otherObject != null) { @@ -1897,20 +1899,10 @@ function move(dr, dc) { occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); // gravity loop - var stateToAnimationIndex = {}; if (isGravity()) for (var fallHeight = 1; ; fallHeight++) { - var serializedState = serializeObjects(level.objects); - var infiniteLoopStartIndex = stateToAnimationIndex[serializedState]; - if (infiniteLoopStartIndex != null) { - // infinite loop - animationQueue.push([0, [INFINITE_LOOP, animationQueue.length - infiniteLoopStartIndex]]); - break; - } else { - stateToAnimationIndex[serializedState] = animationQueue.length; - } // do portals separate from falling logic if (portalActivationLocations.length === 1) { - var portalAnimations = [500]; + var portalAnimations = [300]; if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { animationQueue.push(portalAnimations); } @@ -2166,18 +2158,20 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) var location = newLocations[i]; if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile var otherObject = findObjectAtLocation(location); - if (otherObject != null && otherObject !== object) return; // blocked by object + if (otherObject != null && otherObject !== object) return false; // blocked by object } // zappo presto! var oldState = serializeObjectState(object); object.locations = newLocations; - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (level.map[location] == BUBBLE || level.map[location] == CLOUD) //changed this despite bubble working perfectly without it - paintTileAtLocation(location, SPACE, changeLog); - } changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + animations.push([ + "t" + object.type, // TELEPORT_SNAKE | TELEPORT_BLOCK + object.id, + delta.r, + delta.c, + ]); + return true; } function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { @@ -2689,11 +2683,21 @@ function render() { drawQuarterPie(r, c, radiusFactor, snakeColors[3], 3); break; case PORTAL: - var grd = context.createRadialGradient(c * tileSize + tileSize / 2, r * tileSize + tileSize / 2, tileSize / 12, c * tileSize + tileSize / 2, r * tileSize + tileSize / 2, tileSize / 2); - grd.addColorStop(.5, "black"); - grd.addColorStop(1, "rgba(255, 255, 255, .1)"); - if (activePortalLocations.indexOf(location) !== -1) drawCircle(r, c, 1, grd); - else drawCircle(r, c, 1, "#111"); + context.save(); + if (activePortalLocations.indexOf(location) !== -1) { + context.fillStyle = "black"; + context.strokeStyle = "white"; + context.shadowColor = "white"; + context.shadowBlur = 5; + context.lineWidth = 3; + context.beginPath(); + context.arc(c * tileSize + tileSize / 2, r * tileSize + tileSize / 1.8, tileSize / 2, 0, 2 * Math.PI); + context.closePath(); + context.fill(); + context.stroke(); + } + else drawCircle(r, c, 1, "#999"); + context.restore(); break; case PLATFORM: drawPlatform(r, c, getAdjacentTiles()); @@ -3067,14 +3071,15 @@ function render() { function drawBubble(r, c) { bubbleX = c * tileSize; var grd = context.createRadialGradient(bubbleX, r * tileSize, 0, bubbleX, r * tileSize, tileSize); - grd.addColorStop(0, "rgba(255,255,255,.9)"); - grd.addColorStop(1, "rgba(255,255,255,.2)"); + grd.addColorStop(0, "rgba(255,255,255,1)"); + grd.addColorStop(.4, "rgba(220,255,255,.5)"); + grd.addColorStop(1, "rgba(0,100,255,.1)"); context.fillStyle = grd; - context.lineWidth = .5; - context.strokeStyle = "rgba(200,200,200,.2)"; + context.lineWidth = 1; + context.strokeStyle = "rgba(255,255,255,.05)"; context.beginPath(); - context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, tileSize / 2, 0, 2 * Math.PI); + context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, tileSize / 1.5, 0, 2 * Math.PI); context.fill(); context.stroke(); } @@ -3748,12 +3753,13 @@ function render() { r2 = rTmp; c2 = cTmp; } - var xLo = (c1 + 0.3) * tileSize; - var yLo = (r1 + 0.3) * tileSize; - var xHi = (c2 + 0.45) * tileSize; - var yHi = (r2 + 0.45) * tileSize; + var connectorSize = .38; + var xLo = (c1 + connectorSize) * tileSize; + var yLo = (r1 + connectorSize) * tileSize; + var xHi = (c2 + 1 - connectorSize) * tileSize; + var yHi = (r2 + 1 - connectorSize) * tileSize; context.fillStyle = color; - context.fillRect(xLo + .15 * tileSize, yLo + .15 * tileSize, xHi - xLo, yHi - yLo); + context.fillRect(xLo, yLo, xHi - xLo, yHi - yLo); } function drawBlock(block) { var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); @@ -3764,7 +3770,7 @@ function render() { var r = rowcol.r + animationDisplacementRowcol.r; var c = rowcol.c + animationDisplacementRowcol.c; context.fillStyle = blockColors[block.id % blockColors.length]; - var outlineThickness = .2; + var outlineThickness = .4; var complement = 1 - outlineThickness; var outlinePixels = outlineThickness * tileSize; From 222cf3905787a12404f3df1fdba7081395e3dfbb Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 2 Mar 2020 15:31:48 -0500 Subject: [PATCH 293/577] Update Editor.css --- Editor.css | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/Editor.css b/Editor.css index 9b98df00..a5492e9b 100644 --- a/Editor.css +++ b/Editor.css @@ -9,8 +9,13 @@ button.click-me { font-weight: bold; } +table{ + border-collapse: collapse; +} + td{ text-align: center; + line-height: 16px; } tr{ @@ -26,7 +31,6 @@ button{ background-image: linear-gradient(white, #e6e6e6); border: none; border-radius: 3px; - margin: 2px; box-shadow: .5px .5px 1px black; } @@ -40,6 +44,15 @@ button:active{ color: black; } +#returnButton{ + text-decoration: none; + color: #006666; +} + +.editorButton{ + margin: -1px; /* buttons have built in margins when HTML tags aren't on same line */ +} + #levelTable{ margin: 0 auto; } @@ -56,28 +69,22 @@ button:active{ font-size: 10pt; } -#saveLevelButton{ -} - .standard{ background-color: lightsteelblue; } -.experimental{ - background-color: lightblue; +.controlsHeader{ + line-height: 20px; } -table{ - border-collapse: collapse; +.experimental{ + background-color: lightblue; } .spacer{ height: 10px; } -.controls{ -} - #controls{ background-color: aliceblue; width: 200px; @@ -98,7 +105,7 @@ table{ #levelType{ font-family: Arial; - font-size: 10pt; + font-size: 12pt; } canvas{ From c34cc617b5996f6fdafab8b9fa54a28e7173b240 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 2 Mar 2020 15:31:55 -0500 Subject: [PATCH 294/577] Update Format.css --- Format.css | 92 +++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 21 deletions(-) diff --git a/Format.css b/Format.css index cce1a992..471db521 100644 --- a/Format.css +++ b/Format.css @@ -2,11 +2,12 @@ body{ font-family: Futura; padding-bottom: 50px; background-image: linear-gradient(to bottom right, #fdc122 , #dc6a3f, #d55945, #dc6a3f, #fdc122); - counter-reset: rowNumber -1; + counter-reset: rowNumber 0; } table{ width: 100%; + border-collapse: collapse; } th{ @@ -17,11 +18,8 @@ tr{ height: 30px; } -table tr{ - counter-increment: rowNumber; -} - table tr td:first-child::before { + counter-increment: rowNumber; content: counter(rowNumber); color: rgba(0,0,0,.3); cursor: default; @@ -44,7 +42,7 @@ table tr td:nth-child(2){ } table tr td:nth-child(3){ - width: 35%; + width: 30%; } table tr td:nth-child(4){ @@ -55,21 +53,76 @@ table tr td:nth-child(5){ width: 40%; } +table tr td:nth-child(6){ + width: 5%; +} + td{ - border-radius: 10px; - border: 2px solid transparent; - padding: 5px; + /* border-radius: 10px; + border: 2px solid transparent; */ + padding: 6px; } -td:hover:not(:first-child):not(:last-child){ - border: 2px solid black; - border-radius: 10px; - background-color: rgba(0,0,0,.1); + + +/* +td:hover { + border: 2px solid red; +} +td:hover:first-child { + border-left: 3px solid red; +} +td:hover:nth-child(3n) { + border-right: 4px solid red; } +tr:last-child td:hover { + border-bottom: 4px solid red; +} +td:hover::before, +.row:hover::before, +.ff-fix:hover::before { + background-color: #ffa; + content: '\00a0'; + height: 100%; + left: -5000px; + position: absolute; + top: 0; + width: 10000px; + z-index: -1; +} +td:hover::after, +.col:hover::after, +.ff-fix:hover::after { + background-color: #ffa; + content: '\00a0'; + height: 10000px; + left: 0; + position: absolute; + top: -5000px; + width: 100%; + z-index: -1; +} */ + + + -td.noteColumn:hover{ + +tr:hover{ + background-color: rgba(0,0,0,.05); +} + +table tr td:hover:not(:first-child):not(:nth-child(5)){ + /* border: 2px solid black; + border-radius: 10px; + background-color: rgba(0,0,0,.1); */ + color: blue; } +/* tr td.noteColumn{ + font-size: 10pt !important; + vertical-align: middle; +} */ + a{ color: black; text-decoration: none; @@ -122,7 +175,7 @@ td a{ } .tableContainer{ - width: 50%; + width: 56%; margin: 0 auto; border-spacing: 0; border: 10px solid black; @@ -132,9 +185,6 @@ td a{ margin-bottom: 50px; } -.numberColumn{ -} - .hiddenItem{ filter: blur(8px); pointer-events: none; @@ -142,9 +192,9 @@ td a{ } #showButtonContainer{ - width: 50%; - margin-left: 25%; - margin-right: 25%; + width: 56%; + margin-left: 22%; + margin-right: 22%; position: relative; padding-bottom: 1px; } From e739cc0bded1151b153c25489c5d974a31a4d6ae Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 2 Mar 2020 15:32:05 -0500 Subject: [PATCH 295/577] Update Main.js --- Main.js | 609 +++++++++++++++++++++++++++++--------------------------- 1 file changed, 320 insertions(+), 289 deletions(-) diff --git a/Main.js b/Main.js index fedfadd8..2124014d 100644 --- a/Main.js +++ b/Main.js @@ -24,18 +24,18 @@ var FRUIT_v0 = "3".charCodeAt(0); //legacy var EXIT = "4".charCodeAt(0); var PORTAL = "5".charCodeAt(0); var PLATFORM = "P".charCodeAt(0); -var WOODPLATFORM = "p".charCodeAt(0); +var TRELLIS = "p".charCodeAt(0); var ONEWAYWALLU = "u".charCodeAt(0); var ONEWAYWALLD = "d".charCodeAt(0); -var ONEWAYWALLL = "l".charCodeAt(0); -var ONEWAYWALLR = "r".charCodeAt(0); -var CLOUD = "C".charCodeAt(0); -var BUBBLE = "b".charCodeAt(0); +var TURNSTILEL = "l".charCodeAt(0); +var TURNSTILER = "r".charCodeAt(0); var CLOSEDLIFT = "c".charCodeAt(0); var OPENLIFT = "o".charCodeAt(0); +var CLOUD = "C".charCodeAt(0); +var BUBBLE = "b".charCodeAt(0); var LAVA = "v".charCodeAt(0); var WATER = "w".charCodeAt(0); -var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, CLOSEDLIFT, OPENLIFT, CLOUD, BUBBLE, LAVA, WATER]; +var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, TRELLIS, ONEWAYWALLU, ONEWAYWALLD, TURNSTILEL, TURNSTILER, CLOSEDLIFT, OPENLIFT, CLOUD, BUBBLE, LAVA, WATER]; // object types var SNAKE = "s"; @@ -144,7 +144,7 @@ function parseLevel(string) { }); tileCode = SPACE; } - if (tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; + if (tileCode === PLATFORM || tileCode === TRELLIS || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === TURNSTILEL || tileCode === TURNSTILER || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); level.map.push(tileCode); } @@ -490,7 +490,6 @@ document.addEventListener("keydown", function (event) { if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode("resize"); break; } if (modifierMask === 0) { reset(unmoveStuff); break; } if (modifierMask === SHIFT) { unreset(unmoveStuff); break; } - if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLR); break; } return; case 220: // backslash if (modifierMask === 0) { toggleShowEditor(); break; } @@ -511,8 +510,7 @@ document.addEventListener("keydown", function (event) { case "W".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(WALL); break; } - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(WOODPLATFORM); break; } - if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(WATER); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(WATER); break; } return; case "S".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(1, 0); break; } @@ -524,6 +522,8 @@ document.addEventListener("keydown", function (event) { return; case "X".charCodeAt(0): if (persistentState.showEditor && modifierMask === CTRL) { cutSelection(); break; } + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOSEDLIFT); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(OPENLIFT); break; } return; case "F".charCodeAt(0): if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } @@ -531,7 +531,6 @@ document.addEventListener("keydown", function (event) { return; case "D".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } - if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLD); break; } return; case "B".charCodeAt(0): if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(BLOCK); break; } @@ -540,16 +539,15 @@ document.addEventListener("keydown", function (event) { case "P".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(TRELLIS); break; } return; case "U".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLU); break; } return; case "L".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(-1, 0); break; } - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(CLOSEDLIFT); break; } - if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(OPENLIFT); break; } - if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLL); break; } + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(LAVA); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(WATER); break; } return; case "G".charCodeAt(0): if (modifierMask === 0) { toggleGrid(); break; } @@ -561,13 +559,17 @@ document.addEventListener("keydown", function (event) { if (persistentState.showEditor && modifierMask === CTRL) { copySelection(); break; } return; case "V".charCodeAt(0): - if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(LAVA); break; } if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } case "T".charCodeAt(0): - toggleTheme(); break; - return; + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(TURNSTILEL); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(TURNSTILER); break; } + case "O".charCodeAt(0): + if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(ONEWAYWALLU); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(ONEWAYWALLD); break; } + case 13: //return + if (persistentState.showEditor && modifierMask === 0) { toggleTheme(); break; } case 32: // spacebar - case 9: // tab + case 9: // tab if (modifierMask === 0) { switchSnakes(1); break; } if (modifierMask === SHIFT) { switchSnakes(-1); break; } return; @@ -700,11 +702,11 @@ var paintButtonIdAndTileCodes = [ ["paintPoisonFruitButton", POISON_FRUIT], ["paintPortalButton", PORTAL], ["paintPlatformButton", PLATFORM], - ["paintWoodPlatformButton", WOODPLATFORM], - ["paintOneWayWallUButton", ONEWAYWALLU], + ["paintTrellisButton", TRELLIS], + //["paintOneWayWallUButton", ONEWAYWALLU], ["paintOneWayWallDButton", ONEWAYWALLD], - ["paintOneWayWallLButton", ONEWAYWALLL], - ["paintOneWayWallRButton", ONEWAYWALLR], + ["paintTurnstileLButton", TURNSTILEL], + ["paintTurnstileRButton", TURNSTILER], ["paintClosedLiftButton", CLOSEDLIFT], ["paintOpenLiftButton", OPENLIFT], ["paintCloudButton", CLOUD], @@ -1585,11 +1587,11 @@ function describe(arg1, arg2) { case EXIT: return "an Exit"; case PORTAL: return "a Portal"; case PLATFORM: return "a Platform"; - case WOODPLATFORM: return "a Wooden Platform"; + case TRELLIS: return "a Trellis"; case ONEWAYWALLU: return "a One Way Wall (facing U)"; case ONEWAYWALLD: return "a One Way Wall (facing D)"; - case ONEWAYWALLL: return "a One Way Wall (facing L)"; - case ONEWAYWALLR: return "a One Way Wall (facing R)"; + case TURNSTILEL: return "a One Way Wall (facing L)"; + case TURNSTILER: return "a One Way Wall (facing R)"; case CLOSEDLIFT: return "a Closed Lift"; case OPENLIFT: return "an Open Lift"; case CLOUD: return "a Cloud"; @@ -1733,31 +1735,32 @@ var themeName = "Spring"; var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle, experimentalColors; var curlyOutline = false; -var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; -var bg2 = "rgba(254, 198, 145 * rgba(255, 192, 133"; -var bg3 = "rgba(145, 254, 198 * rgba(117, 255, 192"; -var bg4 = "rgba(7, 7, 83 * rgba(0, 0, 70"; +var bg1 = ["rgba(145, 198, 254", "rgba(133, 192, 255"]; +var bg2 = ["rgba(254, 198, 145", "rgba(255, 192, 133"]; +var bg3 = ["rgba(145, 254, 198", "rgba(117, 255, 192"]; +var bg4 = ["rgba(7, 7, 83", "rgba(0, 0, 70"]; var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; //must be full length to satisfy tint function var snakeColors2 = ["#ff0000", "#00ff00", "#0000ff", "#ffff00"]; var snakeColors3 = ["#BA145C", "#E91624", "#F75802", "#FEFE28"]; -var snakeColors4 = ["#ffffff", "#ffffff", "#ffffff", "#ffffff"]; +var snakeColors4 = ["#000000", "#000000", "#000000", "#000000"]; var fruitColors1 = ["#ff0066", "#ff36a6", "#ff6b1f", "#ff9900", "#ff2600"]; var fruitColors2 = ["black", "black", "black", "black", "black"]; -var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spike, support, box, bolt -var spikeColors2 = ["gray", "black", "white", "black"]; +var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spokes, supports, box, bolt +var spikeColors2 = ["#333", "#333", "#111", "#333"]; var spikeColors3 = ["#333", "#333", "#333", "#777"]; -var blockColors1 = ["#de5a6d", "#fa65dd", "#c367e3", "#9c62fa", "#625ff0"]; //must be full length to satisfy tint function -var blockColors2 = ["#ffffff"]; -var blockColors3 = ["#de7913", "#7d46a0", "#39868b", "#41ccc2", "#ded800"]; -var blockColors4 = ["#150612", "#a52e8b", "#990077", "#d917af", "#4d003c"]; +var blockColors1 = ["#de5a6d", "#fa65dd", "#c367e3", "#9c62fa", "#625ff0"]; //must be 6-digit hex colors to satisfy tint function +var blockColors2 = ["#ffffff", "#999999", "#555555", "#000000"]; +var blockColors3 = ["#de7913", "#7d46a0", "#39868b", "#41ccc2", "#ccc500"]; +var blockColors4 = ["#660050", "#990033", "#b32400", "#e6b800 ", "#008000"]; +var blockColors5 = ["#ffccff", "#ffc2b3", "#ffffcc", "#ccffe6", "#ccffff"]; var fontSize = tileSize * 5; var textStyle1 = ["" + fontSize + "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose -var textStyle2 = ["" + fontSize + "px Impact", "#5702c6", "#ff0098"]; +var textStyle2 = ["" + fontSize + "px Impact", "#400080", "#ff6600"]; var textStyle3 = ["" + fontSize + "px Impact", "#BA145C", "#F75802"]; var textStyle4 = ["" + fontSize + "px Impact", "#ff0", "#f00"]; @@ -1773,7 +1776,7 @@ var themes = [ //name, background, material, surface, curlyOutline, blockColors ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], - ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors4, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] + ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors5, spikeColors2, "white", "white", textStyle1, experimentalColors1] ]; @@ -2059,13 +2062,13 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects return false; } addIfNotPresent(pushedObjects, yetAnotherObject); - if (level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work + if (level.map[forwardLocation] === TRELLIS) addIfNotPresent(forwardLocations, forwardLocation); } else addIfNotPresent(forwardLocations, forwardLocation); } } // check forward locations - for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform, saw no effect but left new code + for (var i = 0; i < forwardLocations.length; i++) { var forwardLocation = forwardLocations[i]; // many of these locations can be inside objects, // but that means the tile must be air, @@ -2177,12 +2180,12 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { switch (tileCode) { case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; - case WOODPLATFORM: case BUBBLE: return pusher != null; + case TRELLIS: case BUBBLE: return pusher != null; case PLATFORM: return dr != 1; case ONEWAYWALLU: return dr != 1; case ONEWAYWALLD: return dr != -1; - case ONEWAYWALLL: return dc != 1; - case ONEWAYWALLR: return dc != -1; + case TURNSTILEL: return dc != 1; + case TURNSTILER: return dc != -1; default: return false; } } @@ -2374,20 +2377,19 @@ function render() { textStyle = themes[themeCounter][10]; experimentalColors = themes[themeCounter][11]; - if (background.substr(0, 1) == "#") { + if (!Array.isArray(background)) { context.fillStyle = background; context.fillRect(0, 0, canvas.width, canvas.height); } else { for (var i = 0; i < level.width; i++) { //checkerboard background for (var j = 0; j < level.height; j++) { - var bgColor1 = background.substr(0, background.indexOf('*')); - var bgColor2 = background.substr(background.indexOf('*') + 2, background.length); + var bgColor1 = background[0]; + var bgColor2 = background[1]; var shade = (j + 1) * .03 + .5; if ((i + j) % 2 == 0) context.fillStyle = bgColor1 + ", " + shade + ")"; else context.fillStyle = bgColor2 + ", " + shade + ")"; context.fillRect(i * tileSize, j * tileSize, tileSize, tileSize); - //context.fillText(i+" "+j,i*tileSize, j*tileSize); } } } @@ -2521,7 +2523,7 @@ function render() { for (var c = 0; c < level.width; c++) { var location = getLocation(level, r, c); var tileCode = level.map[location]; - drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids + drawTile(tileCode, r, c, level, location, true); } } } @@ -2531,6 +2533,16 @@ function render() { if (object.type === SNAKE || object.type === BLOCK) drawObject(object); //draws snakes and blocks } + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + location = getLocation(level, r, c); + tileCode = level.map[location]; + if (tileCode === WATER || tileCode === LAVA) drawTile(tileCode, r, c, level, location, false); //draws only walls + } + } + } + if (onlyTheseObjects == null) { for (var r = 0; r < level.height; r++) { for (var c = 0; c < level.width; c++) { @@ -2546,7 +2558,7 @@ function render() { for (var c = 0; c < level.width; c++) { location = getLocation(level, r, c); tileCode = level.map[location]; - if (tileCode === CLOUD || tileCode === LAVA || tileCode === WATER) drawTile(tileCode, r, c, level, location, false); //draws only clouds + if (tileCode === TURNSTILER || tileCode === TURNSTILEL || tileCode === CLOUD || tileCode === BUBBLE) drawTile(tileCode, r, c, level, location, false); } } } @@ -2601,7 +2613,7 @@ function render() { context.shadowOffsetY = 5; context.shadowColor = "rgba(0,0,0,0.5)"; context.shadowBlur = 4; - var textString = "X"; + var textString = "\u2716"; var textWidth = context.measureText(textString).width; context.fillText(textString, (canvas.width / 2) - (textWidth / 2), canvas.height / 2); } @@ -2620,10 +2632,6 @@ function render() { if (typeof paintBrushTileCode === "number") { if (level.map[hoverLocation] !== paintBrushTileCode) { drawTile(paintBrushTileCode, hoverRowcol.r, hoverRowcol.c, level, hoverLocation); - if (paintBrushTileCode === PLATFORM) { - // make it bolder - hoverAlpha = 0.4; - } } } else if (paintBrushTileCode === SNAKE) { if (!(objectHere != null && objectHere.type === SNAKE && objectHere.id === paintBrushSnakeColorIndex)) { @@ -2691,7 +2699,7 @@ function render() { context.shadowBlur = 5; context.lineWidth = 3; context.beginPath(); - context.arc(c * tileSize + tileSize / 2, r * tileSize + tileSize / 1.8, tileSize / 2, 0, 2 * Math.PI); + context.arc(c * tileSize + tileSize / 2, r * tileSize + tileSize / 2, tileSize / 1.7, 0, 2 * Math.PI); context.closePath(); context.fill(); context.stroke(); @@ -2702,20 +2710,20 @@ function render() { case PLATFORM: drawPlatform(r, c, getAdjacentTiles()); break; - case WOODPLATFORM: - drawOneWayWall("#D38345", r, c, -1, 0); + case TRELLIS: + drawTrellis(r, c); break; case ONEWAYWALLU: - drawOneWayWall("#111", r, c, -1, 0); + drawOneWayWall(r, c, -1); break; case ONEWAYWALLD: - drawOneWayWall("#111", r, c, 1, 0); + drawOneWayWall(r, c, 1); break; - case ONEWAYWALLL: - drawOneWayWall("#111", r, c, 0, -1); + case TURNSTILEL: + drawTurnstile(r, c, -1); break; - case ONEWAYWALLR: - drawOneWayWall("#111", r, c, 0, 1); + case TURNSTILER: + drawTurnstile(r, c, 1); break; case CLOSEDLIFT: drawLift(r, c, false); @@ -2800,7 +2808,7 @@ function render() { var color = snakeColors[object.id % snakeColors.length]; var colorIndex = object.id % snakeColors.length; var altColor = tint(color, 1.2); - if (themeName === "Classic") altColor = color; + if (snakeColors === snakeColors2) altColor = color; var headRowcol; var orientation = 10; for (var i = 0; i < object.locations.length; i++) { @@ -2926,11 +2934,12 @@ function render() { var color = fruitColors[object.id % fruitColors.length]; var stemColor = themes[themeCounter][9] if (themeName === "Classic") color = "#f0f"; - if (is_poison) { color = "#556815"; stemColor = "black"; } + if (is_poison) { color = "#666600"; stemColor = "black"; } context.fillStyle = color; if (themeName != "Classic") { if (surface == "rainbow") { - context.fillStyle = "black"; + stemColor = "white"; + if (!is_poison) context.fillStyle = "black"; context.lineWidth = tileSize / 8; context.strokeStyle = "white"; resize = tileSize * 1.4; @@ -2966,42 +2975,6 @@ function render() { var tileCode = adjacentTiles[1 + dr][1 + dc]; return tileCode == null || tileCode === PLATFORM; } - - /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*1, r*tileSize); - context.lineTo(c*tileSize, r*tileSize); - context.closePath(); - context.rect(c*tileSize, r*tileSize+tileSize*.2857, tileSize, tileSize*.1429);*/ - - /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.25, r*tileSize+tileSize*.2, c*tileSize+tileSize*.25, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.75, r*tileSize+tileSize*.2, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo((c+1)*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize);*/ - - /*context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.arc((c + 3/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.arc((c + 1/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.lineTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize, r*tileSize);*/ - - //context.closePath(); - //context.fillStyle = "#000066"; - //ontext.fill(); - //context.stroke(); } function newPlatform(r, c, isOccupied) { @@ -3024,11 +2997,78 @@ function render() { } } - function drawOneWayWall(fillStyle, r, c, dr, dc) { + function drawTrellis(r, c) { + context.fillStyle = "white"; + roundRect(context, (c - .05) * tileSize, r * tileSize, tileSize, tileSize * .1, 0, true, false); + roundRect(context, (c - .05) * tileSize, r * tileSize, tileSize * .1, tileSize, 0, true, false); + roundRect(context, (c + .95) * tileSize, r * tileSize, tileSize * .1, tileSize, 0, true, false); + roundRect(context, (c - .05) * tileSize, (r - .2) * tileSize, tileSize * .1, tileSize * .2, 0, true, false); + roundRect(context, (c + .95) * tileSize, (r - .2) * tileSize, tileSize * .1, tileSize * .2, 0, true, false); + } + + function drawTurnstile(r, c, dc) { + if (dc == -1) { + var x1 = c * tileSize; + var x2 = (c + 1) * tileSize; + var y1 = r * tileSize; + var y2 = (r + 1) * tileSize; + var start = c * tileSize; + var light1 = (c + .1) * tileSize; + var light2 = (c + .4) * tileSize; + var lineStart = (c + .25) * tileSize; + var lineEnd = (c + .65) * tileSize; + } + else if (dc == 1) { + var x2 = c * tileSize; + var x1 = (c + 1) * tileSize; + var y1 = r * tileSize; + var y2 = (r + 1) * tileSize; + var start = (c + .5) * tileSize; + var light1 = (c + .9) * tileSize; + var light2 = (c + .6) * tileSize; + var lineStart = (c + .75) * tileSize; + var lineEnd = (c + .35) * tileSize; + } + + var grd = context.createLinearGradient(x1, y1, x2, y2); + grd.addColorStop(0, "#d9d9d9"); + grd.addColorStop(1 / 3, "#ffffff"); + grd.addColorStop(1, "#d9d9d9"); + context.fillStyle = grd; + context.strokeStyle = "white"; + + roundRect(context, start, r * tileSize, tileSize * .5, tileSize, 2, true, false); + + //lights + context.lineWidth = 3; + context.beginPath(); + context.fillStyle = "red"; + context.arc(light1, (r + .11) * tileSize, tileSize / 15, 0, 2 * Math.PI); + context.fill(); + context.beginPath(); + context.fillStyle = "green"; + context.arc(light2, (r + .11) * tileSize, tileSize / 14, 0, 2 * Math.PI); + context.fill(); + + //spokes + context.strokeStyle = context.fillStyle = "#555"; + context.lineWidth = 1.5; + for (var i = .3; i < 1; i += .15) { + context.beginPath(); + context.moveTo(lineStart, (r + i) * tileSize); + context.lineTo(lineEnd, (r + i) * tileSize); + context.closePath(); + context.stroke(); + context.arc(light1, (r + i) * tileSize, tileSize / 24, 0, 2 * Math.PI) + context.fill(); + } + } + + function drawOneWayWall(r, c, dr) { context.lineWidth = 2; context.strokeStyle = "#333"; + context.fillStyle = "orange"; context.beginPath(); - if (dr == -1) { context.moveTo(c * tileSize, r * tileSize + tileSize / 2); context.lineTo(c * tileSize + tileSize / 4, r * tileSize + tileSize / 4); @@ -3043,43 +3083,148 @@ function render() { context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + 3 * tileSize / 4); context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize / 2); } - else if (dc == -1) { - context.moveTo(c * tileSize + tileSize / 2, r * tileSize); - context.lineTo(c * tileSize + tileSize / 4, r * tileSize + tileSize / 4); - context.stroke(); - context.moveTo(c * tileSize + tileSize / 4, r * tileSize + 3 * tileSize / 4); - context.lineTo(c * tileSize + tileSize / 2, r * tileSize + tileSize); - } - else if (dc == 1) { - context.moveTo(c * tileSize + tileSize / 2, r * tileSize); - context.lineTo(c * tileSize + 3 * tileSize / 4, r * tileSize + tileSize / 4); - context.stroke(); - context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + 3 * tileSize / 4); - context.lineTo(c * tileSize + tileSize / 2, r * tileSize + tileSize); - } - context.stroke(); context.lineWidth = 0; - context.fillStyle = fillStyle; if (dr == -1) roundRect(context, c * tileSize - tileSize / 15, r * tileSize - tileSize / 15, tileSize + 2 * tileSize / 15, tileSize / 4 + 2 * tileSize / 15, 2, true, false); else if (dr == 1) roundRect(context, c * tileSize - tileSize / 15, (r + 1) * tileSize - tileSize / 15 - tileSize / 4, tileSize + 2 * tileSize / 15, tileSize / 4 + 2 * tileSize / 15, 2, true, false); - else if (dc == -1) roundRect(context, c * tileSize - tileSize / 15, r * tileSize - tileSize / 15, tileSize / 4 + 2 * tileSize / 15, tileSize + 2 * tileSize / 15, 2, true, false); - else if (dc == 1) roundRect(context, (c + 1) * tileSize - tileSize / 15 - tileSize / 4, r * tileSize - tileSize / 15, tileSize / 4 + 2 * tileSize / 15, tileSize + 2 * tileSize / 15, 2, true, false); } + /* var grd = context.createLinearGradient(c * tileSize, r * tileSize, (c + 1) * tileSize, (r + 1) * tileSize); + grd.addColorStop(0, "rgba(255,255,255,.4)"); + grd.addColorStop(.1, "rgba(255,255,255,.5)"); + grd.addColorStop(.2, "rgba(255,255,255,.3)"); + grd.addColorStop(.3, "rgba(255,255,255,.4)"); + grd.addColorStop(.4, "rgba(255,255,255,.6)"); + grd.addColorStop(.5, "rgba(255,255,255,.5)"); + grd.addColorStop(.6, "rgba(255,255,255,.3)"); + grd.addColorStop(.7, "rgba(255,255,255,.4)"); + grd.addColorStop(.8, "rgba(255,255,255,.5)"); + grd.addColorStop(.9, "rgba(255,255,255,.6)"); + grd.addColorStop(1, "rgba(255,255,255,.5)"); + + context.fillStyle = grd; + roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 2, true, false); + context.save(); + var color1 = color2 = color3 = color4 = "transparent"; + + var preventColor = "rgba(255,0,0,.5)"; + + + context.fillStyle = "black"; + if (type === 0) { + color1 = "black"; + } + else if (type === 1) { + // color1 = "red"; + context.beginPath(); + context.moveTo((c + .4) * tileSize, (r + .2) * tileSize); + context.lineTo((c + .4) * tileSize, (r + .55) * tileSize); + context.lineTo((c + .3) * tileSize, (r + .55) * tileSize); + context.lineTo((c + .5) * tileSize, (r + .8) * tileSize); + context.lineTo((c + .7) * tileSize, (r + .55) * tileSize); + context.lineTo((c + .6) * tileSize, (r + .55) * tileSize); + context.lineTo((c + .6) * tileSize, (r + .2) * tileSize); + context.lineTo((c + .4) * tileSize, (r + .2) * tileSize); + context.closePath(); + context.fill(); + } + else if (type === 2) { + // color3 = "red"; + context.beginPath(); + context.moveTo((c + .6) * tileSize, (r + .8) * tileSize); + context.lineTo((c + .6) * tileSize, (r + .45) * tileSize); + context.lineTo((c + .7) * tileSize, (r + .45) * tileSize); + context.lineTo((c + .5) * tileSize, (r + .2) * tileSize); + context.lineTo((c + .3) * tileSize, (r + .45) * tileSize); + context.lineTo((c + .4) * tileSize, (r + .45) * tileSize); + context.lineTo((c + .4) * tileSize, (r + .8) * tileSize); + context.lineTo((c + .6) * tileSize, (r + .8) * tileSize); + context.closePath(); + context.fill(); + } + else if (type === 3) { + // color4 = "red"; + context.beginPath(); + context.moveTo((c + .2) * tileSize, (r + .6) * tileSize); + context.lineTo((c + .55) * tileSize, (r + .6) * tileSize); + context.lineTo((c + .55) * tileSize, (r + .7) * tileSize); + context.lineTo((c + .8) * tileSize, (r + .5) * tileSize); + context.lineTo((c + .55) * tileSize, (r + .3) * tileSize); + context.lineTo((c + .55) * tileSize, (r + .4) * tileSize); + context.lineTo((c + .2) * tileSize, (r + .4) * tileSize); + context.lineTo((c + .2) * tileSize, (r + .6) * tileSize); + context.closePath(); + context.fill(); + } + else if (type === 4) { + // color2 = "red"; + context.beginPath(); + context.moveTo((c + .8) * tileSize, (r + .6) * tileSize); + context.lineTo((c + .45) * tileSize, (r + .6) * tileSize); + context.lineTo((c + .45) * tileSize, (r + .7) * tileSize); + context.lineTo((c + .2) * tileSize, (r + .5) * tileSize); + context.lineTo((c + .45) * tileSize, (r + .3) * tileSize); + context.lineTo((c + .45) * tileSize, (r + .4) * tileSize); + context.lineTo((c + .8) * tileSize, (r + .4) * tileSize); + context.lineTo((c + .8) * tileSize, (r + .6) * tileSize); + context.closePath(); + context.fill(); + } + + context.strokeStyle = "red"; + context.lineWidth = 2; + context.beginPath(); + context.arc((c + .5) * tileSize, (r + .5) * tileSize, tileSize / 3, 0, 2 * Math.PI); + context.closePath(); + context.stroke(); + + context.beginPath(); + context.moveTo((c + .3) * tileSize, (r + .3) * tileSize); + context.lineTo((c + .7) * tileSize, (r + .7) * tileSize); + context.closePath(); + context.stroke(); + + context.shadowBlur = 3; + context.lineWidth = 3; + context.strokeStyle = color1; + context.beginPath(); + context.moveTo(c * tileSize, r * tileSize); + context.lineTo((c + 1) * tileSize, r * tileSize); + context.closePath(); + context.stroke(); + context.strokeStyle = color2; + context.beginPath(); + context.moveTo((c + 1) * tileSize, r * tileSize); + context.lineTo((c + 1) * tileSize, (r + 1) * tileSize); + context.closePath(); + context.stroke(); + context.strokeStyle = color3; + context.beginPath(); + context.moveTo((c + 1) * tileSize, (r + 1) * tileSize); + context.lineTo(c * tileSize, (r + 1) * tileSize); + context.closePath(); + context.stroke(); + context.strokeStyle = color4; + context.beginPath(); + context.moveTo(c * tileSize, (r + 1) * tileSize); + context.lineTo(c * tileSize, r * tileSize); + context.closePath(); + context.stroke(); + context.restore(); */ + function drawBubble(r, c) { bubbleX = c * tileSize; var grd = context.createRadialGradient(bubbleX, r * tileSize, 0, bubbleX, r * tileSize, tileSize); grd.addColorStop(0, "rgba(255,255,255,1)"); - grd.addColorStop(.4, "rgba(220,255,255,.5)"); - grd.addColorStop(1, "rgba(0,100,255,.1)"); + grd.addColorStop(.5, "rgba(220,255,255,.2)"); + grd.addColorStop(1, "rgba(0,100,255,.05)"); context.fillStyle = grd; context.lineWidth = 1; context.strokeStyle = "rgba(255,255,255,.05)"; context.beginPath(); - context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, tileSize / 1.5, 0, 2 * Math.PI); + context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, tileSize / 1.8, 0, 2 * Math.PI); context.fill(); context.stroke(); } @@ -3096,65 +3241,79 @@ function render() { function newLiquid(r, c, type, isOccupied) { context.save(); var tubColor; + var color1; + var color2; + var color3; if (type == LAVA) { - context.fillStyle = "#ffbf00"; - context.strokeStyle = "red"; + color1 = "red"; + color2 = "#e69900"; + color3 = "#111"; + context.strokeStyle = color1; + context.shadowColor = color1; tubColor = "black"; } else { - context.fillStyle = "#1a8cff"; - context.strokeStyle = "#80ffe5"; + color1 = "#80ffe5"; + color2 = "#1a8cff"; + color3 = "white"; + context.strokeStyle = color1; + context.shadowColor = "white"; tubColor = "white"; } - roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 0, true, false); - context.lineWidth = 3; - context.beginPath(); - context.moveTo(c * tileSize, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .1, c * tileSize + tileSize / 3, r * tileSize + tileSize * .1, c * tileSize + tileSize / 2, r * tileSize + tileSize * .2); - context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .3, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .3, c * tileSize + tileSize, r * tileSize + tileSize * .2); - context.moveTo(c * tileSize, r * tileSize + tileSize * .4); - context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .3, c * tileSize + tileSize / 3, r * tileSize + tileSize * .3, c * tileSize + tileSize / 2, r * tileSize + tileSize * .4); - context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .5, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .5, c * tileSize + tileSize, r * tileSize + tileSize * .4); - context.moveTo(c * tileSize, r * tileSize + tileSize * .6); - context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .5, c * tileSize + tileSize / 3, r * tileSize + tileSize * .5, c * tileSize + tileSize / 2, r * tileSize + tileSize * .6); - context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .7, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .7, c * tileSize + tileSize, r * tileSize + tileSize * .6); - context.moveTo(c * tileSize, r * tileSize + tileSize * .8); - context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .7, c * tileSize + tileSize / 3, r * tileSize + tileSize * .7, c * tileSize + tileSize / 2, r * tileSize + tileSize * .8); - context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .9, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .9, c * tileSize + tileSize, r * tileSize + tileSize * .8); - context.stroke(); + context.shadowBlur = 10; + context.lineWidth = 3.5; + for (var i = -.1; i <= 1; i += .1) { + context.beginPath(); + context.moveTo(c * tileSize, (r + i + .1) * tileSize); + context.bezierCurveTo((c + 1 / 6) * tileSize, (r + i) * tileSize, (c + 1 / 3) * tileSize, (r + i) * tileSize, (c + 1 / 2) * tileSize, (r + i + .1) * tileSize); + context.bezierCurveTo((c + 2 / 3) * tileSize, (r + i + .2) * tileSize, (c + 5 / 6) * tileSize, (r + i + .2) * tileSize, (c + 1) * tileSize, (r + i + .1) * tileSize); + context.stroke(); + context.shadowBlur = 0; + context.shadowColor = "transparent"; + var mod = Math.round((i + .1) * 10) % 3; + switch (mod) { + case 0: context.strokeStyle = color2; break; + case 1: context.strokeStyle = color3; break; + case 2: context.strokeStyle = color1; break; + } + } context.fillStyle = tubColor; if (!isOccupied(-1, 0)) { - if (isOccupied(-1, -1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize - tileSize * .2, tileSize * .2, tileSize * 1.2, 0, true, false); - else roundRect(context, c * tileSize - tileSize * .1, r * tileSize, tileSize * .2, tileSize, 0, true, false); + if (isOccupied(-1, -1)) roundRect(context, c * tileSize - tileSize * .1, (r + .1) * tileSize, tileSize * .2, tileSize * 1.2, 0, true, false); + else roundRect(context, c * tileSize - tileSize * .1, (r - .1) * tileSize, tileSize * .2, tileSize * 1.4, 0, true, false); + } + if (!isOccupied(1, 0)) { + if (isOccupied(1, -1)) roundRect(context, c * tileSize + tileSize * .9, (r + .1) * tileSize, tileSize * .2, tileSize * 1.2, 0, true, false); + else roundRect(context, c * tileSize + tileSize * .9, (r - .1) * tileSize, tileSize * .2, tileSize * 1.4, 0, true, false); } - if (!isOccupied(1, 0)) roundRect(context, c * tileSize + tileSize * .9, r * tileSize, tileSize * .2, tileSize, 0, true, false); if (!isOccupied(0, 1)) { - if (isOccupied(-1, 1) && !isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize + tileSize * .8, tileSize * 1.1, tileSize * .2, 0, true, false); - else if (!isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize, r * tileSize + tileSize * .8, tileSize * 1.3, tileSize * .2, 0, true, false); - else if (isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize + tileSize * .8, tileSize * 1.1, tileSize * .2, 0, true, false); - else roundRect(context, c * tileSize, r * tileSize + tileSize * .8, tileSize, tileSize * .2, 0, true, false); + if (isOccupied(-1, 1) && !isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, (r + 1.05) * tileSize, tileSize * 1.1, tileSize * .25, 0, true, false); + else if (!isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize, (r + 1.05) * tileSize, tileSize * 1.3, tileSize * .25, 0, true, false); + else if (isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, (r + 1.05) * tileSize, tileSize * 1.1, tileSize * .25, 0, true, false); + else roundRect(context, c * tileSize, (r + 1.05) * tileSize, tileSize * 1.1, tileSize * .25, 0, true, false); } context.restore(); } - function drawLift(r, c, isFixed) { + function drawLift(r, c, isOpen) { context.lineWidth = .5; context.strokeStyle = "#777"; var strokeBool = false; - if (!isFixed) { + if (!isOpen) { context.fillStyle = "#e68a00"; roundRect(context, c * tileSize + tileSize * .05, r * tileSize + tileSize, tileSize * .9, tileSize * .2, 2, true, strokeBool); context.fillStyle = "#cc0000"; roundRect(context, c * tileSize + tileSize * .3, r * tileSize + tileSize * .8, tileSize * .4, tileSize * .2, { tl: 2, tr: 2 }, true, strokeBool); } - else if (isFixed) { + else if (isOpen) { context.fillStyle = "#e68a00"; roundRect(context, c * tileSize + tileSize * .05, r * tileSize + tileSize * .8, tileSize * .9, tileSize * .2, 2, true, strokeBool); roundRect(context, c * tileSize + tileSize * .05, r * tileSize, tileSize * .9, tileSize * .2, 2, true, strokeBool); - context.fillStyle = "#333"; + if (themeName != "Midnight Rainbow") context.fillStyle = "#333"; + else context.fillStyle = "gainsboro"; context.beginPath(); context.moveTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .8); @@ -3179,135 +3338,7 @@ function render() { context.lineTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .8); context.closePath(); context.fill(); - - /*context.beginPath(); - context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.9); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.1); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.1); - context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.9); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.9); - context.closePath(); - context.fill(); - - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.9); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.1); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.1); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.9); - context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.9); - context.closePath(); - context.fill();*/ } - - /*var grd = context.createLinearGradient(c*tileSize, r*tileSize, (c+1)*tileSize, (r+1)*tileSize); - grd.addColorStop(0, "rgba(255,255,255,.6)"); - grd.addColorStop(.1, "rgba(255,255,255,.7)"); - grd.addColorStop(.2, "rgba(255,255,255,.5)"); - grd.addColorStop(.3, "rgba(255,255,255,.6)"); - grd.addColorStop(.4, "rgba(255,255,255,.8)"); - grd.addColorStop(.5, "rgba(255,255,255,.7)"); - grd.addColorStop(.6, "rgba(255,255,255,.5)"); - grd.addColorStop(.7, "rgba(255,255,255,.6)"); - grd.addColorStop(.8, "rgba(255,255,255,.7)"); - grd.addColorStop(.9, "rgba(255,255,255,.8)"); - grd.addColorStop(1, "rgba(255,255,255,.7)"); - - context.fillStyle = grd; - roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 5, true, false); - - if(!isFixed){ - var bgColor; - if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*')+2, background.length); - var r1, r2, b1, b2, g1, g2; - r1 = bgColor.substr(5, bgColor.indexOf(",")-5); - g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); - b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); - var shade = (r+1)*.03+.5; - if(shade>1) - shade = 1; - r2 = 255 + (r1-255) * shade - 20; - g2 = 255 + (g1-255) * shade - 20; - b2 = 255 + (b1-255) * shade - 20; - context.strokeStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; - //context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; - - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.5, r*tileSize); - context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.15); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.4); - context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.35); - context.stroke(); - - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.4); - context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.6); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.6); - context.lineTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.5); - context.stroke(); - - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.6); - context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.6); - context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.7); - context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.55, r*tileSize+tileSize*.9); - context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*1); - context.stroke(); - - context.beginPath(); - context.moveTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.6); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.7); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*1); - context.stroke(); - - context.beginPath(); - context.moveTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.3); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.3); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.35); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.6); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.8); - context.stroke(); - - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.35); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.1); - context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.5, r*tileSize); - context.stroke(); - - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.35); - context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); - context.lineTo(c*tileSize+tileSize*.55, r*tileSize+tileSize*.45); - context.lineTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.6); - context.lineTo(c*tileSize+tileSize*.6, r*tileSize+tileSize*.7); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.15, r*tileSize+tileSize*.7); - context.lineTo(c*tileSize+tileSize*.02, r*tileSize+tileSize*.98); - context.stroke(); - - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.5, r*tileSize+tileSize*.35); - context.lineTo(c*tileSize+tileSize*.4, r*tileSize+tileSize*.25); - context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.2); - context.stroke(); - }*/ } function drawWall(r, c, adjacentTiles) { @@ -3374,8 +3405,8 @@ function render() { context.closePath(); var bgColor; - if ((c + r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*') + 2, background.length); + if ((c + r) % 2 == 0) bgColor = background[0]; + else bgColor = background[1]; var r1, r2, b1, b2, g1, g2; r1 = bgColor.substr(5, bgColor.indexOf(",") - 5); g1 = bgColor.substr(bgColor.indexOf(",") + 1, bgColor.indexOf(",") - 4); @@ -3398,8 +3429,8 @@ function render() { context.closePath(); var bgColor; - if ((c + r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*') + 2, background.length); + if ((c + r) % 2 == 0) bgColor = background[0]; + else bgColor = background[1]; var r1, r2, b1, b2, g1, g2; r1 = bgColor.substr(5, bgColor.indexOf(",") - 5); g1 = bgColor.substr(bgColor.indexOf(",") + 1, bgColor.indexOf(",") - 4); From fd42942ffba879e89d26a23734e75c73af12c819 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 2 Mar 2020 15:32:19 -0500 Subject: [PATCH 296/577] Update Framework.html --- Framework.html | 228 +++++++++++++++++++++++++++++++------------------ 1 file changed, 146 insertions(+), 82 deletions(-) diff --git a/Framework.html b/Framework.html index d5949455..ca98b2f0 100644 --- a/Framework.html +++ b/Framework.html @@ -1,95 +1,159 @@ - - Snakefall Redesign - - - - - - - - - - -
    + + + Snakefall Redesign + + + + + + + + + + + + +
    -
    -
    STANDARD LEVEL
    does not contain experimental elements
    - Controls (hover for hotkeys): -
    - Arrows/WASD to move - - - -
    - - Moves: 0+0 - - - - +
    +
    STANDARD + LEVEL
    contains only original Snakebird elements
    + Controls (hover for hotkeys):
    + Arrows/WASD to move + + + +
    + + Moves: 0+0 + + +
    +
    - +
    This game is a clone of Snakebird by Noumenon Games.
    - + + From f18e5bb31b56ad4c3b534cf0eb0a023b3904dc41 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 2 Mar 2020 15:32:37 -0500 Subject: [PATCH 297/577] Update index.html --- index.html | 219 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 143 insertions(+), 76 deletions(-) diff --git a/index.html b/index.html index 5afc9a6d..d6a07680 100644 --- a/index.html +++ b/index.html @@ -31,465 +31,532 @@
    Standard Puzzles
    - Solution + V Level Creator Note + Solution - + Disabilities Act thejoshwolfe + - + Crashing Down thejoshwolfe + - + Etch-a-sketch inukoblainc + - + Fruit Fall XeroOl + - + Block Valley XeroOl + - + Block Valley 2 XeroOl + - + Spike Maze XeroOl + - + Fruit Maze XeroOl + - + Box Bridge XeroOl + - + Please add animations XeroOl + - + The Ordeal thejoshwolfe + - + Coral Block XeroOl + - + Adventure XeroOl + - + Sky Grid XeroOl + - + Block Train XeroOl + - + Turn Around XeroOl + - + Turn Around 2 XeroOl + - + There and Back Again gavinksong + - + You Don't Have To Wait For Animations thejoshwolfe + - + Keyhole XeroOl + - + Block Train 2 XeroOl + - + Fruit Maze 2 XeroOl + + - + Tight Space XeroOl + - + Floating Fruits XeroOl + - + Skyscraper XeroOl + - + Fruit Maze 3 XeroOl + - + Fruit Maze 4 XeroOl + - + Fruit Maze 5 XeroOl + - + Fruit Maze 6 XeroOl + - + Disarm XeroOl + - + Level 1 DoctorEndugu + - + Level 2 DoctorEndugu + - + Bumpy Road XeroOl + - + Level 0 "Checkmark Underpass" Teal Knight + - + Level 1 "Hanging spikes" Teal Knight + - + Level 2 "Trap Mine" Teal Knight + - + Level 3 "The Servant" Teal Knight + - + Level 4 "Greed that goes well" Teal Knight + - + Level 5 "Collapse" Teal Knight + - + Level 6 "Decisions" Teal Knight + - + Level 1 Cookie + - + Level 2 Cookie + - + Level 3 Cookie + - + Level 3 2 Joel Fox - Derived from Cookie's level above + Derived from Cookie's level above + - + Balancing Act IHNN + - + Temple Joel Fox + - + Renovated Temple Joel Fox - Addresses a common criticism of Temple + Addresses a common criticism of Temple + - + Basilica Gooby - Based on Joel's levels above + Based on Joel's levels above + - + The Birdcage Gooby + - + The Birds Uncaged Joel Fox - Derived from Gooby's level above + Derived from Gooby's level above + - + Stripped Gooby - Based on The Birdcage and The Birds Uncaged + Based on The Birdcage and The Birds Uncaged + - + Serpentine Collaboration Created by Gooby & Joel Fox + - + The Sawmill Gooby + - + The Hardmill Joel Fox - Derived from Gooby's level above + Derived from Gooby's level above + - + Mine Rescue Gooby - Allow time for solution to load + Allow time for solution to load + - + Fruit Temple XeroI0 - I'm sorry + I'm sorry + - + Plane Crash Gooby - Novelty Guess-the-Exit Special + Novelty Guess-the-Exit Special + - + Top Shelf Gooby + - + Top Shelf 2 Gooby + - + Plinko Gooby + - + The Puppet Master Gooby + - + Rainbow Bridge Gooby + - + Castle Gooby + - + Perch Gooby + - + Black Mamba Gooby +
    @@ -568,7 +635,7 @@ - + Bundók Gooby From 175b1009f5d925927a960d96e6d411ba3c6e839d Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 15:13:47 -0500 Subject: [PATCH 298/577] Update Editor.css --- Editor.css | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/Editor.css b/Editor.css index a5492e9b..905775fd 100644 --- a/Editor.css +++ b/Editor.css @@ -85,6 +85,10 @@ button:active{ height: 10px; } +.hotkeySpacer{ + display: none; +} + #controls{ background-color: aliceblue; width: 200px; @@ -111,3 +115,53 @@ button:active{ canvas{ border: 2px solid black; } + +.hotkey{ + font-size: 6pt; + color: gray; + font-family: Arial; +} + +.buttonDiv{ + display: inline-block; +} + +#controlButtons{ + margin: 0 auto; + margin-top: 10px; + margin-bottom: 10px; + display: table; +} + +#switchSnakesButton{ + height: 30px; + margin-right: 10px; +} + +#arrowsHolder{ + display: flex; + align-items: center; +} + +.arrow{ + height: 30px; + width: 30px; + font-size: 14pt; + font-family: Futura; +} + +#arrowLeft{ + float: left; + margin-right: 5px; +} + +#verticalArrowsHolder{ + float: left; + width: fit-content; +} + +#arrowRight{ + float: left; + margin-left: 5px; +} + From 4772c1087a1c4a1fcb0d47304b7335bc59425e47 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 15:14:02 -0500 Subject: [PATCH 299/577] Update index.html --- index.html | 108 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/index.html b/index.html index d6a07680..2ada21dc 100644 --- a/index.html +++ b/index.html @@ -565,80 +565,91 @@
    Experimental Puzzles
    - Solution + V Level Creator Note + Solution - + Under Cover XeroOl + - + Snake Filter XeroOl + - + Platformway to Heaven thejoshwolfe + - + Under Cover 2 XeroOl + - + Low Clearance XeroOl + - + Baited Trap XeroOl + - + Gateway to Freedom LevelWorld + - + House on Fire Gooby + - + Cloud 9 Gooby + - + Bundók Gooby +
    @@ -647,52 +658,59 @@
    nohatcoder Puzzles
    - Solution + V Level Creator Note + Solution - + Fruity Gap nohatcoder + - + Bridge nohatcoder + - + Abyss nohatcoder + - + Tube nohatcoder + - + Tunnel nohatcoder + - + Transport edderiofer, nohatcoder, & Gooby +
    @@ -701,52 +719,59 @@
    Avis Anguis Puzzles
    - Solution + Verification Level Creator Note + Solution - + Demo Terzalo + - + Level A Connorses + - + Level B Connorses + - + Level 1 CHz + - + Level 2 CHz + - + Level 3 CHz +
    @@ -755,80 +780,91 @@
    Gameboy Puzzles
    - Solution + V Level Creator Note + Solution - + Level 1 freeball1 + - + Level 2 freeball1 + - + Level 3 freeball1 + - + Level 4 freeball1 + - + Level 5 freeball1 + - + Level 6 freeball1 + - + Level 7 freeball1 + - + Level 8 freeball1 + - + Level 9 freeball1 + - + Level 10 freeball1 + From ad9f0f27acb717688245a766efc13a7632d72411 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 15:14:11 -0500 Subject: [PATCH 300/577] Update Format.css --- Format.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Format.css b/Format.css index 471db521..99995604 100644 --- a/Format.css +++ b/Format.css @@ -261,3 +261,7 @@ form{ filter: blur(8px); visibility: hidden;*/ } + +.vColumn{ + font-size: 10pt; +} From 056da159ae4553bfdecdd78dec709af53526219f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 15:14:20 -0500 Subject: [PATCH 301/577] Update Main.js --- Main.js | 44 ++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/Main.js b/Main.js index 2124014d..eee09cfe 100644 --- a/Main.js +++ b/Main.js @@ -560,6 +560,8 @@ document.addEventListener("keydown", function (event) { return; case "V".charCodeAt(0): if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } + case "H".charCodeAt(0): + if (modifierMask === 0) { toggleHotkeys(); break; } case "T".charCodeAt(0): if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(TURNSTILEL); break; } if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(TURNSTILER); break; } @@ -623,8 +625,27 @@ function switchSnakes(delta) { } activeSnakeId = snakes[0].id; } +document.getElementById("arrowUp").addEventListener("click", function () { + move(-1, 0); + return; +}); +document.getElementById("arrowDown").addEventListener("click", function () { + move(1, 0); + return; +}); +document.getElementById("arrowLeft").addEventListener("click", function () { + move(0, -1); + return; +}); +document.getElementById("arrowRight").addEventListener("click", function () { + move(0, 1); + return; +}); document.getElementById("showGridButton").addEventListener("click", function () { - toggleGrid(); + toggleHotkeys(); +}); +document.getElementById("hideHotkeyButton").addEventListener("click", function () { + }); document.getElementById("saveProgressButton").addEventListener("click", function () { saveReplay(); @@ -658,6 +679,21 @@ function toggleGrid() { savePersistentState(); render(); } +function toggleHotkeys() { + persistentState.hideHotkeys = !persistentState.hideHotkeys; + savePersistentState(); + var hotkeys = document.getElementsByClassName("hotkey"); + var spacers = document.getElementsByClassName("hotkeySpacer"); + for (var i = 0; i < hotkeys.length; i++) { + if (persistentState.hideHotkeys) hotkeys[i].style.display = "block"; + else hotkeys[i].style.display = "none"; + } + for (var i = 0; i < spacers.length; i++) { + if (persistentState.hideHotkeys) spacers[i].style.display = "none"; + else spacers[i].style.display = "block"; + } + render(); +} ["serializationTextarea", "shareLinkTextbox"].forEach(function (id) { document.getElementById(id).addEventListener("keydown", function (event) { @@ -1705,6 +1741,7 @@ function haveCheatcodesBeenUsed() { var persistentState = { showEditor: false, showGrid: false, + hideHotkeys: false, }; function savePersistentState() { localStorage.snakefall = JSON.stringify(persistentState); @@ -1716,6 +1753,7 @@ function loadPersistentState() { } persistentState.showEditor = !!persistentState.showEditor; persistentState.showGrid = !!persistentState.showGrid; + persistentState.hideHotkeys = !!persistentState.hideHotkeys; showEditorChanged(); } var isGravityEnabled = true; @@ -2136,6 +2174,7 @@ function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations }); if (activatingPortals.length === 1) { // exactly one new portal we're touching. activate it + //drawObject(newSnake("white", object.locations)); portalActivationLocations.push(activatingPortals[0]); } }); @@ -2449,6 +2488,7 @@ function render() { // throw this in there somewhere document.getElementById("showGridButton").textContent = (persistentState.showGrid ? "Hide" : "Show") + " Grid"; + document.getElementById("hideHotkeyButton").textContent = (persistentState.hideHotkeys ? "Hide" : "Show") + " Hotkeys"; if (animationProgress < 1.0) requestAnimationFrame(render); return; // this is the end of the function proper @@ -2558,7 +2598,7 @@ function render() { for (var c = 0; c < level.width; c++) { location = getLocation(level, r, c); tileCode = level.map[location]; - if (tileCode === TURNSTILER || tileCode === TURNSTILEL || tileCode === CLOUD || tileCode === BUBBLE) drawTile(tileCode, r, c, level, location, false); + if (tileCode === TURNSTILER || tileCode === TURNSTILEL || tileCode === CLOUD || tileCode === BUBBLE || tileCode === TRELLIS) drawTile(tileCode, r, c, level, location, false); } } } From 15c0af7fe0bfd5625bf0cf14543368e4491b81a9 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 15:14:30 -0500 Subject: [PATCH 302/577] Update Framework.html --- Framework.html | 82 +++++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 38 deletions(-) diff --git a/Framework.html b/Framework.html index ca98b2f0..a52f84c2 100644 --- a/Framework.html +++ b/Framework.html @@ -55,20 +55,20 @@ Static - - - - +

    W
    +

    S
    +

    Shift  E
    +

    A
    + - Kinetic - - - +

    Shift  S
    +

    F
    +

    B
    - + Experimental Elements @@ -76,43 +76,43 @@ Kinetic - - - +

    Shift  F
    +

    C
    +

    Shift  B
    + - Platforms - - - +

    P
    +

    Shift  P
    +

    Shift  O
    + - Scissor Lifts - - +

    X
    +

    Shift  X
    + - Turnstiles - - +

    T
    +

    Shift  T
    + - Liquids - - +

    L
    +

    Shift  L
    - + @@ -123,21 +123,27 @@
    STANDARD LEVEL
    contains only original Snakebird elements
    Controls (hover for hotkeys):
    - Arrows/WASD to move - - - -
    + Arrows/WASD to move
    +
    +
    +
    + +
    + + +
    + +
    +
    + Moves: 0+0 - -
    - +
    + + + + From 44b859634862515a3649be1bb8dbefca9497d70f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 15:18:24 -0500 Subject: [PATCH 303/577] Update Main.js --- Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.js b/Main.js index eee09cfe..47e2c558 100644 --- a/Main.js +++ b/Main.js @@ -1741,7 +1741,7 @@ function haveCheatcodesBeenUsed() { var persistentState = { showEditor: false, showGrid: false, - hideHotkeys: false, + hideHotkeys: true, }; function savePersistentState() { localStorage.snakefall = JSON.stringify(persistentState); From 1ac42c3274cacef5fa84578ac75e59e0f5539804 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 15:23:38 -0500 Subject: [PATCH 304/577] Update SolutionVerification.html --- SolutionVerification.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SolutionVerification.html b/SolutionVerification.html index 98615645..4bd57788 100644 --- a/SolutionVerification.html +++ b/SolutionVerification.html @@ -1,7 +1,7 @@ Snakefall Redesign - + From 85a2d718f7b5793dda5507cc74811e1955f359e0 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 15:25:50 -0500 Subject: [PATCH 305/577] Update Main.js --- Main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Main.js b/Main.js index 47e2c558..9b36e065 100644 --- a/Main.js +++ b/Main.js @@ -642,10 +642,10 @@ document.getElementById("arrowRight").addEventListener("click", function () { return; }); document.getElementById("showGridButton").addEventListener("click", function () { - toggleHotkeys(); + toggleGrid(); }); document.getElementById("hideHotkeyButton").addEventListener("click", function () { - + toggleHotkeys(); }); document.getElementById("saveProgressButton").addEventListener("click", function () { saveReplay(); @@ -2578,7 +2578,7 @@ function render() { for (var c = 0; c < level.width; c++) { location = getLocation(level, r, c); tileCode = level.map[location]; - if (tileCode === WATER || tileCode === LAVA) drawTile(tileCode, r, c, level, location, false); //draws only walls + if (tileCode === WATER || tileCode === LAVA || tileCode === SPIKE) drawTile(tileCode, r, c, level, location, false); //draws only walls } } } From efef4d2cf901f5565a04d0ef3a9f96b3976d1b44 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 16:23:11 -0500 Subject: [PATCH 306/577] Update Main.js --- Main.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Main.js b/Main.js index 9b36e065..e66c9e07 100644 --- a/Main.js +++ b/Main.js @@ -641,6 +641,9 @@ document.getElementById("arrowRight").addEventListener("click", function () { move(0, 1); return; }); +document.getElementById("bigButtonButton").addEventListener("click", function () { + toggleButtonSize(); +}); document.getElementById("showGridButton").addEventListener("click", function () { toggleGrid(); }); @@ -674,6 +677,20 @@ function toggleShowEditor() { savePersistentState(); showEditorChanged(); } +function toggleButtonSize() { + persistentState.bigButton = !persistentState.bigButton; + savePersistentState(); + var buttons = document.getElementsByClassName("bottomButton"); + if (persistentState.bigButton) { + for (var i = 0; i < buttons.length; i++) + buttons[i].classList.add("bigButton"); + } + else { + for (var i = 0; i < buttons.length; i++) + buttons[i].classList.remove("bigButton"); + } + render(); +} function toggleGrid() { persistentState.showGrid = !persistentState.showGrid; savePersistentState(); @@ -1740,6 +1757,7 @@ function haveCheatcodesBeenUsed() { var persistentState = { showEditor: false, + bigButton: false, showGrid: false, hideHotkeys: true, }; @@ -1752,6 +1770,7 @@ function loadPersistentState() { } catch (e) { } persistentState.showEditor = !!persistentState.showEditor; + persistentState.bigButton = !!persistentState.bigButton; persistentState.showGrid = !!persistentState.showGrid; persistentState.hideHotkeys = !!persistentState.hideHotkeys; showEditorChanged(); @@ -2489,6 +2508,7 @@ function render() { // throw this in there somewhere document.getElementById("showGridButton").textContent = (persistentState.showGrid ? "Hide" : "Show") + " Grid"; document.getElementById("hideHotkeyButton").textContent = (persistentState.hideHotkeys ? "Hide" : "Show") + " Hotkeys"; + document.getElementById("bigButtonButton").textContent = (persistentState.bigButton ? "Regular" : "Giant") + " Buttons"; if (animationProgress < 1.0) requestAnimationFrame(render); return; // this is the end of the function proper From 388536a3899244b81aeba57f852e2e8bcca9adca Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 16:23:30 -0500 Subject: [PATCH 307/577] Update Editor.css --- Editor.css | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Editor.css b/Editor.css index 905775fd..9e09b090 100644 --- a/Editor.css +++ b/Editor.css @@ -134,7 +134,7 @@ canvas{ } #switchSnakesButton{ - height: 30px; + min-height: 30px; margin-right: 10px; } @@ -144,8 +144,8 @@ canvas{ } .arrow{ - height: 30px; - width: 30px; + min-height: 30px; + min-width: 30px; font-size: 14pt; font-family: Futura; } @@ -165,3 +165,7 @@ canvas{ margin-left: 5px; } +.bigButton{ + font-size: 20pt; + padding: 10px; +} From 33f25a3148dc6c56c09a63e24ca8fe40d91254e5 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 16:23:49 -0500 Subject: [PATCH 308/577] Update Framework.html --- Framework.html | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/Framework.html b/Framework.html index a52f84c2..6f0808c7 100644 --- a/Framework.html +++ b/Framework.html @@ -82,7 +82,7 @@ - Platforms + Platforms

    P

    Shift  P
    @@ -125,25 +125,26 @@ Controls (hover for hotkeys):
    Arrows/WASD to move
    -
    +
    - +
    - - + +
    - +
    - - - Moves: 0+0 - -
    - - - - + + + Moves: 0+0 + +
    + + + + + From ad2ee3158c3fc3dfbb8b977390ff9c0dfb44bbba Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 16:49:01 -0500 Subject: [PATCH 309/577] Update Framework.html --- Framework.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Framework.html b/Framework.html index 6f0808c7..345bd158 100644 --- a/Framework.html +++ b/Framework.html @@ -58,7 +58,7 @@

    W

    S

    Shift  E
    -

    A
    +

    P
    @@ -84,9 +84,9 @@ Platforms -

    P
    -

    Shift  P
    -

    Shift  O
    +

    M
    +

    Shift  M
    +

    Ctrl  M
    - - Scissor Lifts + + One Way Platforms -

    X
    -

    Shift  X
    +

    O
    +

    SHIFT  O
    @@ -106,6 +102,13 @@

    Shift  T
    + + Scissor Lifts + +

    X
    +

    Shift  X
    + + Liquids From 4e8b28df61aed834eac6b16638358a79ddb6b840 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 17:02:53 -0500 Subject: [PATCH 313/577] Update Main.js --- Main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Main.js b/Main.js index 27646683..c48ce6a3 100644 --- a/Main.js +++ b/Main.js @@ -565,10 +565,10 @@ document.addEventListener("keydown", function (event) { if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(TURNSTILER); break; } case "O".charCodeAt(0): if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(ONEWAYWALLU); break; } + if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(ONEWAYWALLD); break; } case "M".charCodeAt(0): if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(TRELLIS); break; } - if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode(ONEWAYWALLD); break; } case 13: //return if (persistentState.showEditor && modifierMask === 0) { toggleTheme(); break; } case 32: // spacebar @@ -757,7 +757,7 @@ var paintButtonIdAndTileCodes = [ ["paintPortalButton", PORTAL], ["paintPlatformButton", PLATFORM], ["paintTrellisButton", TRELLIS], - //["paintOneWayWallUButton", ONEWAYWALLU], + ["paintOneWayWallUButton", ONEWAYWALLU], ["paintOneWayWallDButton", ONEWAYWALLD], ["paintTurnstileLButton", TURNSTILEL], ["paintTurnstileRButton", TURNSTILER], From fd139f7c94366dd211869bd1b543e609a657097f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 17:07:15 -0500 Subject: [PATCH 314/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index b50d2978..07e8347f 100644 --- a/Framework.html +++ b/Framework.html @@ -143,7 +143,7 @@ Moves: 0+0
    - + From 09b67c1dd1b3a48f016a46c8240d051daf027f00 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 17:08:02 -0500 Subject: [PATCH 315/577] Update Main.js --- Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.js b/Main.js index c48ce6a3..c1e6a1db 100644 --- a/Main.js +++ b/Main.js @@ -2509,7 +2509,7 @@ function render() { // throw this in there somewhere document.getElementById("showGridButton").textContent = (persistentState.showGrid ? "Hide" : "Show") + " Grid"; document.getElementById("hideHotkeyButton").textContent = (persistentState.hideHotkeys ? "Hide" : "Show") + " Hotkeys"; - document.getElementById("bigButtonButton").textContent = (persistentState.bigButton ? "Regular" : "Giant") + " Buttons"; + document.getElementById("bigButtonButton").textContent = (persistentState.bigButton ? "Regular" : "Large") + " Buttons"; if (animationProgress < 1.0) requestAnimationFrame(render); return; // this is the end of the function proper From 6022880f6f453225f4f64d9c8e5a4c338005b35b Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 17:15:57 -0500 Subject: [PATCH 316/577] Update Main.js --- Main.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/Main.js b/Main.js index c1e6a1db..a5bd6eb7 100644 --- a/Main.js +++ b/Main.js @@ -2120,7 +2120,7 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects return false; } addIfNotPresent(pushedObjects, yetAnotherObject); - if (level.map[forwardLocation] === TRELLIS) addIfNotPresent(forwardLocations, forwardLocation); + if (level.map[forwardLocation] === TRELLIS || level.map[forwardLocation] === ONEWAYWALLU) addIfNotPresent(forwardLocations, forwardLocation); } else addIfNotPresent(forwardLocations, forwardLocation); } @@ -2142,7 +2142,6 @@ function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects addIfNotPresent(dyingObjects, object); continue; } - } else if (tileCode === LAVA) { if (object.type === SNAKE || object.type === BLOCK) { @@ -2472,13 +2471,6 @@ function render() { drawGrid(); } - // active snake halo - /*if (countSnakes() !== 0 && isAlive()) { - var activeSnake = findActiveSnake(); - var activeSnakeRowcol = getRowcol(level, activeSnake.locations[0]); - drawCircle(activeSnakeRowcol.r, activeSnakeRowcol.c, 2, "rgba(256,256,256,0.3)"); - }*/ - if (persistentState.showEditor) { if (paintBrushTileCode === BLOCK) { if (paintBrushBlockId != null) { From 2d8fa4bcd04c93b87c45b1b18e27db374093335b Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 18:03:39 -0500 Subject: [PATCH 317/577] Update index.html --- index.html | 112 ++++++++++++++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/index.html b/index.html index 2ada21dc..41dd7121 100644 --- a/index.html +++ b/index.html @@ -71,7 +71,7 @@ - + Block Valley XeroOl @@ -79,7 +79,7 @@ - + Block Valley 2 XeroOl @@ -87,7 +87,7 @@ - + Spike Maze XeroOl @@ -95,7 +95,7 @@ - + Fruit Maze XeroOl @@ -103,15 +103,15 @@ - - Box Bridge + + Box Bridge XeroOl - + Please add animations XeroOl @@ -119,7 +119,7 @@ - + The Ordeal thejoshwolfe @@ -127,7 +127,7 @@ - + Coral Block XeroOl @@ -135,7 +135,7 @@ - + Adventure XeroOl @@ -143,7 +143,7 @@ - + Sky Grid XeroOl @@ -151,7 +151,7 @@ - + Block Train XeroOl @@ -159,7 +159,7 @@ - + Turn Around XeroOl @@ -167,7 +167,7 @@ - + Turn Around 2 XeroOl @@ -175,15 +175,15 @@ - - There and Back Again + + There and Back Again gavinksong - + You Don't Have To Wait For Animations thejoshwolfe @@ -191,7 +191,7 @@ - + Keyhole XeroOl @@ -199,7 +199,7 @@ - + Block Train 2 XeroOl @@ -207,7 +207,7 @@ - + Fruit Maze 2 XeroOl @@ -216,7 +216,7 @@ - + Tight Space XeroOl @@ -228,11 +228,11 @@ Floating Fruits XeroOl - + - + Skyscraper XeroOl @@ -240,7 +240,7 @@ - + Fruit Maze 3 XeroOl @@ -280,7 +280,7 @@ - + Level 1 DoctorEndugu @@ -288,7 +288,7 @@ - + Level 2 DoctorEndugu @@ -296,7 +296,7 @@ - + Bumpy Road XeroOl @@ -304,7 +304,7 @@ - + Level 0 "Checkmark Underpass" Teal Knight @@ -312,7 +312,7 @@ - + Level 1 "Hanging spikes" Teal Knight @@ -320,7 +320,7 @@ - + Level 2 "Trap Mine" Teal Knight @@ -328,7 +328,7 @@ - + Level 3 "The Servant" Teal Knight @@ -336,7 +336,7 @@ - + Level 4 "Greed that goes well" Teal Knight @@ -344,7 +344,7 @@ - + Level 5 "Collapse" Teal Knight @@ -352,7 +352,7 @@ - + Level 6 "Decisions" Teal Knight @@ -360,7 +360,7 @@ - + Level 1 Cookie @@ -368,7 +368,7 @@ - + Level 2 Cookie @@ -376,7 +376,7 @@ - + Level 3 Cookie @@ -384,7 +384,7 @@ - + Level 3 2 Joel Fox Derived from Cookie's level above @@ -392,7 +392,7 @@ - + Balancing Act IHNN @@ -408,7 +408,7 @@ - + Renovated Temple Joel Fox Addresses a common criticism of Temple @@ -416,7 +416,7 @@ - + Basilica Gooby Based on Joel's levels above @@ -424,7 +424,7 @@ - + The Birdcage Gooby @@ -432,7 +432,7 @@ - + The Birds Uncaged Joel Fox Derived from Gooby's level above @@ -440,7 +440,7 @@ - + Stripped Gooby Based on The Birdcage and The Birds Uncaged @@ -456,7 +456,7 @@ - + The Sawmill Gooby @@ -464,7 +464,7 @@ - + The Hardmill Joel Fox Derived from Gooby's level above @@ -472,7 +472,7 @@ - + Mine Rescue Gooby Allow time for solution to load @@ -488,7 +488,7 @@ - + Plane Crash Gooby Novelty Guess-the-Exit Special @@ -496,7 +496,7 @@ - + Top Shelf Gooby @@ -504,7 +504,7 @@ - + Top Shelf 2 Gooby @@ -512,7 +512,7 @@ - + Plinko Gooby @@ -520,7 +520,7 @@ - + The Puppet Master Gooby @@ -528,7 +528,7 @@ - + Rainbow Bridge Gooby @@ -536,7 +536,7 @@ - + Castle Gooby @@ -544,7 +544,7 @@ - + Perch Gooby @@ -552,7 +552,7 @@ - + Black Mamba Gooby From 0d35ac8ce3ec1b63df0677fe2380660a49e1955d Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 18:38:00 -0500 Subject: [PATCH 318/577] Update Framework.html --- Framework.html | 54 +++++++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/Framework.html b/Framework.html index 07e8347f..67606b1d 100644 --- a/Framework.html +++ b/Framework.html @@ -102,7 +102,7 @@

    Shift  T
    - + Scissor Lifts

    X
    @@ -121,33 +121,37 @@ -
    -
    -
    STANDARD - LEVEL
    contains only original Snakebird elements
    -
    CONTROLS
    hover for hotkeys
    -
    use keyboard arrows or WASD to move, or use the buttons below
    -
    -
    -
    - -
    - - +
    +
    +
    CONTROLS
    hover for hotkeys
    +
    +
    use the arrows or WASD keys on your keyboard to move, or use the buttons below
    +
    +
    +
    + +
    + + +
    +
    -
    - - - Moves: 0+0 - -
    - - - - - +
    +
    +
    STANDARD LEVEL
    contains only original Snakebird elements
    + + Moves: 0+0 +
    + +

    + +
    + +
    + +
    From 1b84fe567bf77199f9d091cb6dec1fa340dc6b62 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 18:38:13 -0500 Subject: [PATCH 319/577] Update Editor.css --- Editor.css | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Editor.css b/Editor.css index 9e09b090..e5eea1c6 100644 --- a/Editor.css +++ b/Editor.css @@ -110,6 +110,8 @@ button:active{ #levelType{ font-family: Arial; font-size: 12pt; + color:slateblue; + margin: 0 0 10px 0; } canvas{ @@ -169,3 +171,26 @@ canvas{ font-size: 20pt; padding: 10px; } + +#bottomBlock{ + text-align: center; + vertical-align: top; +} + +#separator{ + background-color: black; + height: 150px; + width: 1px; + margin: 0 5px 0 5px; + display: inline-block; +} + +.optionsHeader{ + margin-top: 10px; + font-family: Futura; +} + +#keyboardInstructions{ + font-size: 8pt; + width: 220px; +} From 8ff0e1070b9395d24d93ca7a732c971dd3e36a38 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 18:49:08 -0500 Subject: [PATCH 320/577] Update SolutionVerification.js --- SolutionVerification.js | 6452 +++++++++++++++++++-------------------- 1 file changed, 3216 insertions(+), 3236 deletions(-) diff --git a/SolutionVerification.js b/SolutionVerification.js index 847deb92..fdc1d4dc 100644 --- a/SolutionVerification.js +++ b/SolutionVerification.js @@ -1,7 +1,7 @@ function unreachable() { return new Error("unreachable"); } if (typeof VERSION !== "undefined") { - document.getElementById("versionSpan").innerHTML = - '' + VERSION.tag + ''; + document.getElementById("versionSpan").innerHTML = + '' + VERSION.tag + ''; } /*$(document).ready(function() { var fruits1 = getObjectsOfType(FRUIT); @@ -50,30 +50,30 @@ var cs = false; var tileSize = 34; var level; -var unmoveStuff = {undoStack:[], redoStack:[], spanId:"movesSpan", undoButtonId:"unmoveButton", redoButtonId:"removeButton"}; -var uneditStuff = {undoStack:[], redoStack:[], spanId:"editsSpan", undoButtonId:"uneditButton", redoButtonId:"reeditButton"}; +var unmoveStuff = { undoStack: [], redoStack: [], spanId: "movesSpan", undoButtonId: "unmoveButton", redoButtonId: "removeButton" }; +var uneditStuff = { undoStack: [], redoStack: [], spanId: "editsSpan", undoButtonId: "uneditButton", redoButtonId: "reeditButton" }; var paradoxes = []; function loadLevel(newLevel) { - level = newLevel; - currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); - - activateAnySnakePlease(); - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - undoStuffChanged(unmoveStuff); - uneditStuff.undoStack = []; - uneditStuff.redoStack = []; - undoStuffChanged(uneditStuff); - blockSupportRenderCache = {}; - render(); + level = newLevel; + currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); + + activateAnySnakePlease(); + unmoveStuff.undoStack = []; + unmoveStuff.redoStack = []; + undoStuffChanged(unmoveStuff); + uneditStuff.undoStack = []; + uneditStuff.redoStack = []; + undoStuffChanged(uneditStuff); + blockSupportRenderCache = {}; + render(); } var magicNumber_v0 = "3tFRIoTU"; -var magicNumber = "HyRr4JK1"; +var magicNumber = "HyRr4JK1"; var exampleLevel = magicNumber_v0 + "&" + - "17&31" + - "?" + + "17&31" + + "?" + "0000000000000000000000000000000" + "0000000000000000000000000000000" + "0000000000000000000000000000000" + @@ -91,389 +91,389 @@ var exampleLevel = magicNumber_v0 + "&" + "0000011111111101111111111100000" + "0000001111111100111111111100000" + "0000001111111000111111111100000" + - "/" + - "s0 ?351&350&349/" + - "f0 ?328/" + - "f1 ?366/"; + "/" + + "s0 ?351&350&349/" + + "f0 ?328/" + + "f1 ?366/"; var testLevel_v0 = "3tFRIoTU&5&5?0005*00300024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/"; var testLevel_v0_converted = "HyRr4JK1&5&5?0005*4024005*001000/b0?7&6&15&23/s3?18/s0?1&0&5/s1?2/s4?10/s2?17/b2?9/b3?14/b4?19/b1?4&20/b5?24/f0?8/"; function parseLevel(string) { - // magic number - var cursor = 0; - skipWhitespace(); - var versionTag = string.substr(cursor, magicNumber.length); - switch (versionTag) { - case magicNumber_v0: - case magicNumber: break; - default: throw new Error("not a snakefall level"); - } - cursor += magicNumber.length; - consumeKeyword("&"); - - var level = { - height: -1, - width: -1, - map: [], - objects: [], - }; - - // height, width - level.height = readInt(); - consumeKeyword("&"); - level.width = readInt(); - - // map - var mapData = readRun(); - mapData = decompressSerialization(mapData); - if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); - var upconvertedObjects = []; - var fruitCount = 0; - var tileCounter = 0; - for (var i = 0; i < mapData.length; i++) { - var tileCode = mapData[i].charCodeAt(0); - if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { - // fruit used to be a tile code. now it's an object. - upconvertedObjects.push({ - type: FRUIT, - id: fruitCount++, - dead: false, // unused - locations: [i], - }); - tileCode = SPACE; - } - if(tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; - if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); - level.map.push(tileCode); - } - - // objects - skipWhitespace(); - while (cursor < string.length) { - var object = { - type: "?", - id: -1, - dead: false, - locations: [], + // magic number + var cursor = 0; + skipWhitespace(); + var versionTag = string.substr(cursor, magicNumber.length); + switch (versionTag) { + case magicNumber_v0: + case magicNumber: break; + default: throw new Error("not a snakefall level"); + } + cursor += magicNumber.length; + consumeKeyword("&"); + + var level = { + height: -1, + width: -1, + map: [], + objects: [], }; - // type - object.type = string[cursor]; - var locationsLimit; - if (object.type === SNAKE) locationsLimit = -1; - else if (object.type === BLOCK) locationsLimit = -1; - else if (object.type === FRUIT) locationsLimit = 1; - else throw parserError("expected object type code"); - cursor += 1; - - // id - object.id = readInt(); - - // locations - var locationsData = readRun(); - var locationStrings = locationsData.split("&"); - if (locationStrings.length === 0) throw parserError("locations must be non-empty"); - if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); - - locationStrings.forEach(function(locationString) { - var location = parseInt(locationString); - if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); - object.locations.push(location); - }); + // height, width + level.height = readInt(); + consumeKeyword("&"); + level.width = readInt(); + + // map + var mapData = readRun(); + mapData = decompressSerialization(mapData); + if (level.height * level.width !== mapData.length) throw parserError("height, width, and map.length do not jive"); + var upconvertedObjects = []; + var fruitCount = 0; + var tileCounter = 0; + for (var i = 0; i < mapData.length; i++) { + var tileCode = mapData[i].charCodeAt(0); + if (tileCode === FRUIT_v0 && versionTag === magicNumber_v0) { + // fruit used to be a tile code. now it's an object. + upconvertedObjects.push({ + type: FRUIT, + id: fruitCount++, + dead: false, // unused + locations: [i], + }); + tileCode = SPACE; + } + if (tileCode === PLATFORM || tileCode === WOODPLATFORM || tileCode === ONEWAYWALLU || tileCode === ONEWAYWALLD || tileCode === ONEWAYWALLL || tileCode === ONEWAYWALLR || tileCode === CLOSEDLIFT || tileCode === OPENLIFT || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER) tileCounter++; + if (validTileCodes.indexOf(tileCode) === -1) throw parserError("invalid tilecode: " + JSON.stringify(mapData[i])); + level.map.push(tileCode); + } - level.objects.push(object); + // objects skipWhitespace(); - } - - for (var i = 0; i < upconvertedObjects.length; i++) { - level.objects.push(upconvertedObjects[i]); - } + while (cursor < string.length) { + var object = { + type: "?", + id: -1, + dead: false, + locations: [], + }; - return level; + // type + object.type = string[cursor]; + var locationsLimit; + if (object.type === SNAKE) locationsLimit = -1; + else if (object.type === BLOCK) locationsLimit = -1; + else if (object.type === FRUIT) locationsLimit = 1; + else throw parserError("expected object type code"); + cursor += 1; + + // id + object.id = readInt(); + + // locations + var locationsData = readRun(); + var locationStrings = locationsData.split("&"); + if (locationStrings.length === 0) throw parserError("locations must be non-empty"); + if (locationsLimit !== -1 && locationStrings.length > locationsLimit) throw parserError("too many locations"); + + locationStrings.forEach(function (locationString) { + var location = parseInt(locationString); + if (!(0 <= location && location < level.map.length)) throw parserError("location out of bounds: " + JSON.stringify(locationString)); + object.locations.push(location); + }); - function skipWhitespace() { - while (" \n\t\r".indexOf(string[cursor]) !== -1) { - cursor += 1; + level.objects.push(object); + skipWhitespace(); } - } - function consumeKeyword(keyword) { - skipWhitespace(); - if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); - cursor += 1; - } - function readInt() { - skipWhitespace(); - for (var i = cursor; i < string.length; i++) { - if ("0123456789".indexOf(string[i]) === -1) break; + + for (var i = 0; i < upconvertedObjects.length; i++) { + level.objects.push(upconvertedObjects[i]); + } + + return level; + + function skipWhitespace() { + while (" \n\t\r".indexOf(string[cursor]) !== -1) { + cursor += 1; + } + } + function consumeKeyword(keyword) { + skipWhitespace(); + if (string.indexOf(keyword, cursor) !== cursor) throw parserError("expected " + JSON.stringify(keyword)); + cursor += 1; + } + function readInt() { + skipWhitespace(); + for (var i = cursor; i < string.length; i++) { + if ("0123456789".indexOf(string[i]) === -1) break; + } + var substring = string.substring(cursor, i); + if (substring.length === 0) throw parserError("expected int"); + cursor = i; + return parseInt(substring, 10); + } + function readRun() { + consumeKeyword("?"); + var endIndex = string.indexOf("/", cursor); + var substring = string.substring(cursor, endIndex); + cursor = endIndex + 1; + return substring; + } + function parserError(message) { + return new Error("parse error at position " + cursor + ": " + message); } - var substring = string.substring(cursor, i); - if (substring.length === 0) throw parserError("expected int"); - cursor = i; - return parseInt(substring, 10); - } - function readRun() { - consumeKeyword("?"); - var endIndex = string.indexOf("/", cursor); - var substring = string.substring(cursor, endIndex); - cursor = endIndex + 1; - return substring; - } - function parserError(message) { - return new Error("parse error at position " + cursor + ": " + message); - } } function serializeTileCode(tileCode) { - return String.fromCharCode(tileCode); + return String.fromCharCode(tileCode); } function stringifyLevel(level) { - var output = magicNumber + "&"; - output += level.height + "&" + level.width + "\n"; + var output = magicNumber + "&"; + output += level.height + "&" + level.width + "\n"; - output += "?\n"; - for (var r = 0; r < level.height; r++) { - output += " " + level.map.slice(r * level.width, (r + 1) * level.width).map(serializeTileCode).join("") + "\n"; - } - output += "/\n"; + output += "?\n"; + for (var r = 0; r < level.height; r++) { + output += " " + level.map.slice(r * level.width, (r + 1) * level.width).map(serializeTileCode).join("") + "\n"; + } + output += "/\n"; - output += serializeObjects(level.objects); + output += serializeObjects(level.objects); - // sanity check - var shouldBeTheSame = parseLevel(output); - if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken + // sanity check + var shouldBeTheSame = parseLevel(output); + if (!deepEquals(level, shouldBeTheSame)) throw asdf; // serialization/deserialization is broken - return output; + return output; } function serializeObjects(objects) { - var output = ""; - for (var i = 0; i < objects.length; i++) { - var object = objects[i]; - output += object.type + object.id + " "; - output += "?" + object.locations.join("&") + "/\n"; - } - return output; + var output = ""; + for (var i = 0; i < objects.length; i++) { + var object = objects[i]; + output += object.type + object.id + " "; + output += "?" + object.locations.join("&") + "/\n"; + } + return output; } function serializeObjectState(object) { - if (object == null) return [0,[]]; - return [object.dead, copyArray(object.locations)]; + if (object == null) return [0, []]; + return [object.dead, copyArray(object.locations)]; } var base66 = "----0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; function compressSerialization(string) { - string = string.replace(/\s+/g, ""); - // run-length encode several 0's in a row, etc. - // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) - var result = ""; - var runStart = 0; - for (var i = 1; i < string.length + 1; i++) { - var runLength = i - runStart; - if (string[i] === string[runStart] && runLength < base66.length - 1) continue; - // end of run - if (runLength >= 4) { - // compress - result += "*" + base66[runLength] + string[runStart]; - } else { - // literal - result += string.substring(runStart, i); + string = string.replace(/\s+/g, ""); + // run-length encode several 0's in a row, etc. + // 2000000000000003 -> 2*A03 ("A" is 14 in base66 defined above) + var result = ""; + var runStart = 0; + for (var i = 1; i < string.length + 1; i++) { + var runLength = i - runStart; + if (string[i] === string[runStart] && runLength < base66.length - 1) continue; + // end of run + if (runLength >= 4) { + // compress + result += "*" + base66[runLength] + string[runStart]; + } else { + // literal + result += string.substring(runStart, i); + } + runStart = i; } - runStart = i; - } - return result; + return result; } function decompressSerialization(string) { - string = string.replace(/\s+/g, ""); - var result = ""; - for (var i = 0; i < string.length; i++) { - if (string[i] === "*") { - i += 1; - var runLength = base66.indexOf(string[i]); - i += 1; - var char = string[i]; - for (var j = 0; j < runLength; j++) { - result += char; - } - } else { - result += string[i]; + string = string.replace(/\s+/g, ""); + var result = ""; + for (var i = 0; i < string.length; i++) { + if (string[i] === "*") { + i += 1; + var runLength = base66.indexOf(string[i]); + i += 1; + var char = string[i]; + for (var j = 0; j < runLength; j++) { + result += char; + } + } else { + result += string[i]; + } } - } - return result; + return result; } var replayMagicNumber = "nmGTi8PB"; function stringifyReplay() { - var output = replayMagicNumber + "&"; - // only specify the snake id in an input if it's different from the previous. - // the first snake index is 0 to optimize for the single-snake case. - var currentSnakeId = 0; - for (var i = 0; i < unmoveStuff.undoStack.length; i++) { - var firstChange = unmoveStuff.undoStack[i][0]; - if (firstChange[0] !== "i") throw unreachable(); - var snakeId = firstChange[1]; - var dr = firstChange[2]; - var dc = firstChange[3]; - var directionCode; - if (dr ===-1 && dc === 0) directionCode = "u"; - else if (dr === 0 && dc ===-1) directionCode = "l"; - else if (dr === 1 && dc === 0) directionCode = "d"; - else if (dr === 0 && dc === 1) directionCode = "r"; - else throw unreachable(); - if (snakeId !== currentSnakeId) { - output += snakeId; // int to string - currentSnakeId = snakeId; + var output = replayMagicNumber + "&"; + // only specify the snake id in an input if it's different from the previous. + // the first snake index is 0 to optimize for the single-snake case. + var currentSnakeId = 0; + for (var i = 0; i < unmoveStuff.undoStack.length; i++) { + var firstChange = unmoveStuff.undoStack[i][0]; + if (firstChange[0] !== "i") throw unreachable(); + var snakeId = firstChange[1]; + var dr = firstChange[2]; + var dc = firstChange[3]; + var directionCode; + if (dr === -1 && dc === 0) directionCode = "u"; + else if (dr === 0 && dc === -1) directionCode = "l"; + else if (dr === 1 && dc === 0) directionCode = "d"; + else if (dr === 0 && dc === 1) directionCode = "r"; + else throw unreachable(); + if (snakeId !== currentSnakeId) { + output += snakeId; // int to string + currentSnakeId = snakeId; + } + output += directionCode; } - output += directionCode; - } - return output; + return output; } function parseAndLoadReplay(string) { - string = decompressSerialization(string); - var expectedPrefix = replayMagicNumber + "&"; - if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); - var cursor = expectedPrefix.length; - - // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. - activeSnakeId = 0; - while (cursor < string.length) { - var snakeIdStr = ""; - var c = string.charAt(cursor); - cursor += 1; - while ('0' <= c && c <= '9') { - snakeIdStr += c; - if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); - c = string.charAt(cursor); - cursor += 1; - } - if (snakeIdStr.length > 0) { - activeSnakeId = parseInt(snakeIdStr); - // don't just validate when switching snakes, but on every move. - } + string = decompressSerialization(string); + var expectedPrefix = replayMagicNumber + "&"; + if (string.substring(0, expectedPrefix.length) !== expectedPrefix) throw new Error("unrecognized replay string"); + var cursor = expectedPrefix.length; + + // the starting snakeid is 0, which may not exist, but we only validate it when doing a move. + activeSnakeId = 0; + while (cursor < string.length) { + var snakeIdStr = ""; + var c = string.charAt(cursor); + cursor += 1; + while ('0' <= c && c <= '9') { + snakeIdStr += c; + if (cursor >= string.length) throw new Error("replay string has unexpected end of input"); + c = string.charAt(cursor); + cursor += 1; + } + if (snakeIdStr.length > 0) { + activeSnakeId = parseInt(snakeIdStr); + // don't just validate when switching snakes, but on every move. + } - // doing a move. - if (!getSnakes().some(function(snake) { - return snake.id === activeSnakeId; - })) { - throw new Error("invalid snake id: " + activeSnakeId); - } - switch (c) { - case 'l': move( 0, -1); break; - case 'u': move(-1, 0); break; - case 'r': move( 0, 1); break; - case 'd': move( 1, 0); break; - default: throw new Error("replay string has invalid direction: " + c); + // doing a move. + if (!getSnakes().some(function (snake) { + return snake.id === activeSnakeId; + })) { + throw new Error("invalid snake id: " + activeSnakeId); + } + switch (c) { + case 'l': move(0, -1); break; + case 'u': move(-1, 0); break; + case 'r': move(0, 1); break; + case 'd': move(1, 0); break; + default: throw new Error("replay string has invalid direction: " + c); + } } - } - // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. - reset(unmoveStuff); - document.getElementById("removeButton").classList.add("click-me"); + // now that the replay was executed successfully, undo it all so that it's available in the redo buffer. + reset(unmoveStuff); + document.getElementById("removeButton").classList.add("click-me"); } var currentSerializedLevel; function saveLevel() { - if (isDead()) return alert("Can't save while you're dead!"); - var serializedLevel = compressSerialization(stringifyLevel(level)); - currentSerializedLevel = serializedLevel; - var hash = "#level=" + serializedLevel; - expectHash = hash; - location.hash = hash; - - // This marks a starting point for solving the level. - unmoveStuff.undoStack = []; - unmoveStuff.redoStack = []; - editorHasBeenTouched = false; - undoStuffChanged(unmoveStuff); + if (isDead()) return alert("Can't save while you're dead!"); + var serializedLevel = compressSerialization(stringifyLevel(level)); + currentSerializedLevel = serializedLevel; + var hash = "#level=" + serializedLevel; + expectHash = hash; + location.hash = hash; + + // This marks a starting point for solving the level. + unmoveStuff.undoStack = []; + unmoveStuff.redoStack = []; + editorHasBeenTouched = false; + undoStuffChanged(unmoveStuff); } function saveReplay() { - if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); - // preserve the level in the url bar. - var hash = "#level=" + currentSerializedLevel; - if (dirtyState === REPLAY_DIRTY) { - // there is a replay to save - hash += "#replay=" + compressSerialization(stringifyReplay()); - } - expectHash = hash; - location.hash = hash; + if (dirtyState === EDITOR_DIRTY) return alert("Can't save a replay with unsaved editor changes."); + // preserve the level in the url bar. + var hash = "#level=" + currentSerializedLevel; + if (dirtyState === REPLAY_DIRTY) { + // there is a replay to save + hash += "#replay=" + compressSerialization(stringifyReplay()); + } + expectHash = hash; + location.hash = hash; } function deepEquals(a, b) { - if (a == null) return b == null; - if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; - if (Array.isArray(a)) { - if (!Array.isArray(b)) return false; - if (a.length !== b.length) return false; - for (var i = 0; i < a.length; i++) { - if (!deepEquals(a[i], b[i])) return false; + if (a == null) return b == null; + if (typeof a === "string" || typeof a === "number" || typeof a === "boolean") return a === b; + if (Array.isArray(a)) { + if (!Array.isArray(b)) return false; + if (a.length !== b.length) return false; + for (var i = 0; i < a.length; i++) { + if (!deepEquals(a[i], b[i])) return false; + } + return true; + } + // must be objects + var aKeys = Object.keys(a); + var bKeys = Object.keys(b); + if (aKeys.length !== bKeys.length) return false; + aKeys.sort(); + bKeys.sort(); + if (!deepEquals(aKeys, bKeys)) return false; + for (var i = 0; i < aKeys.length; i++) { + if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; } return true; - } - // must be objects - var aKeys = Object.keys(a); - var bKeys = Object.keys(b); - if (aKeys.length !== bKeys.length) return false; - aKeys.sort(); - bKeys.sort(); - if (!deepEquals(aKeys, bKeys)) return false; - for (var i = 0; i < aKeys.length; i++) { - if (!deepEquals(a[aKeys[i]], b[bKeys[i]])) return false; - } - return true; } function getLocation(level, r, c) { - if (!isInBounds(level, r, c)) throw unreachable(); - return r * level.width + c; + if (!isInBounds(level, r, c)) throw unreachable(); + return r * level.width + c; } function getRowcol(level, location) { - if (location < 0 || location >= level.width * level.height) throw unreachable(); - var r = Math.floor(location / level.width); - var c = location % level.width; - return {r:r, c:c}; + if (location < 0 || location >= level.width * level.height) throw unreachable(); + var r = Math.floor(location / level.width); + var c = location % level.width; + return { r: r, c: c }; } function isInBounds(level, r, c) { - if (c < 0 || c >= level.width) return false;; - if (r < 0 || r >= level.height) return false;; - return true; + if (c < 0 || c >= level.width) return false;; + if (r < 0 || r >= level.height) return false;; + return true; } function offsetLocation(location, dr, dc) { - var rowcol = getRowcol(level, location); - return getLocation(level, rowcol.r + dr, rowcol.c + dc); + var rowcol = getRowcol(level, location); + return getLocation(level, rowcol.r + dr, rowcol.c + dc); } -document.getElementById("checkSolutionButton").addEventListener("click", function() { - redoAll(unmoveStuff); +document.getElementById("checkSolutionButton").addEventListener("click", function () { + redoAll(unmoveStuff); }); -document.getElementById("unmoveButton").addEventListener("click", function() { - undo(unmoveStuff); - render(); +document.getElementById("unmoveButton").addEventListener("click", function () { + undo(unmoveStuff); + render(); }); -document.getElementById("removeButton").addEventListener("click", function() { - redo(unmoveStuff); - render(); +document.getElementById("removeButton").addEventListener("click", function () { + redo(unmoveStuff); + render(); }); -["serializationTextarea", "shareLinkTextbox"].forEach(function(id) { - document.getElementById(id).addEventListener("keydown", function(event) { - // let things work normally - event.stopPropagation(); - }); +["serializationTextarea", "shareLinkTextbox"].forEach(function (id) { + document.getElementById(id).addEventListener("keydown", function (event) { + // let things work normally + event.stopPropagation(); + }); }); -document.getElementById("submitSerializationButton").addEventListener("click", function() { - var string = document.getElementById("serializationTextarea").value; - try { - var newLevel = parseLevel(string); - } catch (e) { - alert(e); - return; - } - loadLevel(newLevel); +document.getElementById("submitSerializationButton").addEventListener("click", function () { + var string = document.getElementById("serializationTextarea").value; + try { + var newLevel = parseLevel(string); + } catch (e) { + alert(e); + return; + } + loadLevel(newLevel); }); -document.getElementById("shareLinkTextbox").addEventListener("focus", function() { - setTimeout(function() { - document.getElementById("shareLinkTextbox").select(); - }, 0); +document.getElementById("shareLinkTextbox").addEventListener("focus", function () { + setTimeout(function () { + document.getElementById("shareLinkTextbox").select(); + }, 0); }); var paintBrushTileCode = null; @@ -486,701 +486,701 @@ var resizeDragAnchorRowcol = null; var clipboardData = null; var clipboardOffsetRowcol = null; var paintButtonIdAndTileCodes = [ - ["resizeButton", "resize"], - ["selectButton", "select"], - ["pasteButton", "paste"], + ["resizeButton", "resize"], + ["selectButton", "select"], + ["pasteButton", "paste"], ]; -paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - document.getElementById(id).addEventListener("click", function() { - setPaintBrushTileCode(tileCode); - }); +paintButtonIdAndTileCodes.forEach(function (pair) { + var id = pair[0]; + var tileCode = pair[1]; + document.getElementById(id).addEventListener("click", function () { + setPaintBrushTileCode(tileCode); + }); }); -document.getElementById("uneditButton").addEventListener("click", function() { - undo(uneditStuff); - render(); +document.getElementById("uneditButton").addEventListener("click", function () { + undo(uneditStuff); + render(); }); -document.getElementById("reeditButton").addEventListener("click", function() { - redo(uneditStuff); - render(); +document.getElementById("reeditButton").addEventListener("click", function () { + redo(uneditStuff); + render(); }); -document.getElementById("saveLevelButton").addEventListener("click", function() { - saveLevel(); +document.getElementById("saveLevelButton").addEventListener("click", function () { + saveLevel(); }); -document.getElementById("copyButton").addEventListener("click", function() { - copySelection(); +document.getElementById("copyButton").addEventListener("click", function () { + copySelection(); }); -document.getElementById("cutButton").addEventListener("click", function() { - cutSelection(); +document.getElementById("cutButton").addEventListener("click", function () { + cutSelection(); }); // be careful with location vs rowcol, because this variable is used when resizing var lastDraggingRowcol = null; var hoverLocation = null; var draggingChangeLog = null; -canvas.addEventListener("mousedown", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - var location = getLocationFromEvent(event); - if (persistentState.showEditor && paintBrushTileCode != null) { - // editor tool - lastDraggingRowcol = getRowcol(level, location); - if (paintBrushTileCode === "select") selectionStart = location; - if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; - draggingChangeLog = []; - paintAtLocation(location, draggingChangeLog); - } else { - // playtime - var object = findObjectAtLocation(location); - if (object == null) return; - if (object.type !== SNAKE) return; - // active snake - activeSnakeId = object.id; - render(); - } -}); -canvas.addEventListener("dblclick", function(event) { - if (event.altKey) return; - if (event.button !== 0) return; - event.preventDefault(); - if (persistentState.showEditor && paintBrushTileCode === "select") { - // double click with select tool +canvas.addEventListener("mousedown", function (event) { + if (event.altKey) return; + if (event.button !== 0) return; + event.preventDefault(); var location = getLocationFromEvent(event); - var object = findObjectAtLocation(location); - if (object == null) return; - stopDragging(); - if (object.type === SNAKE) { - // edit snakes of this color - paintBrushTileCode = SNAKE; - paintBrushSnakeColorIndex = object.id % snakeColors.length; - } else if (object.type === BLOCK) { - // edit this particular block - paintBrushTileCode = BLOCK; - paintBrushBlockId = object.id; - } else if (object.type === FRUIT) { - // edit fruits, i guess - paintBrushTileCode = FRUIT; - } else throw unreachable(); - paintBrushTileCodeChanged(); - } + if (persistentState.showEditor && paintBrushTileCode != null) { + // editor tool + lastDraggingRowcol = getRowcol(level, location); + if (paintBrushTileCode === "select") selectionStart = location; + if (paintBrushTileCode === "resize") resizeDragAnchorRowcol = lastDraggingRowcol; + draggingChangeLog = []; + paintAtLocation(location, draggingChangeLog); + } else { + // playtime + var object = findObjectAtLocation(location); + if (object == null) return; + if (object.type !== SNAKE) return; + // active snake + activeSnakeId = object.id; + render(); + } }); -document.addEventListener("mouseup", function(event) { - stopDragging(); +canvas.addEventListener("dblclick", function (event) { + if (event.altKey) return; + if (event.button !== 0) return; + event.preventDefault(); + if (persistentState.showEditor && paintBrushTileCode === "select") { + // double click with select tool + var location = getLocationFromEvent(event); + var object = findObjectAtLocation(location); + if (object == null) return; + stopDragging(); + if (object.type === SNAKE) { + // edit snakes of this color + paintBrushTileCode = SNAKE; + paintBrushSnakeColorIndex = object.id % snakeColors.length; + } else if (object.type === BLOCK) { + // edit this particular block + paintBrushTileCode = BLOCK; + paintBrushBlockId = object.id; + } else if (object.type === FRUIT) { + // edit fruits, i guess + paintBrushTileCode = FRUIT; + } else throw unreachable(); + paintBrushTileCodeChanged(); + } +}); +document.addEventListener("mouseup", function (event) { + stopDragging(); }); function stopDragging() { - if (lastDraggingRowcol != null) { - // release the draggin' - lastDraggingRowcol = null; - paintBrushObject = null; - resizeDragAnchorRowcol = null; - pushUndo(uneditStuff, draggingChangeLog); - draggingChangeLog = null; - } + if (lastDraggingRowcol != null) { + // release the draggin' + lastDraggingRowcol = null; + paintBrushObject = null; + resizeDragAnchorRowcol = null; + pushUndo(uneditStuff, draggingChangeLog); + draggingChangeLog = null; + } } -canvas.addEventListener("mousemove", function(event) { - if (!persistentState.showEditor) return; - var location = getLocationFromEvent(event); - var mouseRowcol = getRowcol(level, location); - if (lastDraggingRowcol != null) { - // Dragging Force - Through the Fruit and Flames - var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); - // we need to get rowcols for everything before we start dragging, because dragging might resize the world. - var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function(location) { - return getRowcol(level, location); - }); - path.forEach(function(rowcol) { - // convert to location at the last minute in case each of these steps is changing the coordinate system. - paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); - }); - lastDraggingRowcol = mouseRowcol; - hoverLocation = null; - } else { - // hovering - if (hoverLocation !== location) { - hoverLocation = location; - render(); +canvas.addEventListener("mousemove", function (event) { + if (!persistentState.showEditor) return; + var location = getLocationFromEvent(event); + var mouseRowcol = getRowcol(level, location); + if (lastDraggingRowcol != null) { + // Dragging Force - Through the Fruit and Flames + var lastDraggingLocation = getLocation(level, lastDraggingRowcol.r, lastDraggingRowcol.c); + // we need to get rowcols for everything before we start dragging, because dragging might resize the world. + var path = getNaiveOrthogonalPath(lastDraggingLocation, location).map(function (location) { + return getRowcol(level, location); + }); + path.forEach(function (rowcol) { + // convert to location at the last minute in case each of these steps is changing the coordinate system. + paintAtLocation(getLocation(level, rowcol.r, rowcol.c), draggingChangeLog); + }); + lastDraggingRowcol = mouseRowcol; + hoverLocation = null; + } else { + // hovering + if (hoverLocation !== location) { + hoverLocation = location; + render(); + } } - } }); -canvas.addEventListener("mouseout", function() { - if (hoverLocation !== location) { - // turn off the hover when the mouse leaves - hoverLocation = null; - render(); - } +canvas.addEventListener("mouseout", function () { + if (hoverLocation !== location) { + // turn off the hover when the mouse leaves + hoverLocation = null; + render(); + } }); function getLocationFromEvent(event) { - var r = Math.floor(eventToMouseY(event, canvas) / tileSize); - var c = Math.floor(eventToMouseX(event, canvas) / tileSize); - // since the canvas is centered, the bounding client rect can be half-pixel aligned, - // resulting in slightly out-of-bounds mouse events. - r = clamp(r, 0, level.height); - c = clamp(c, 0, level.width); - return getLocation(level, r, c); + var r = Math.floor(eventToMouseY(event, canvas) / tileSize); + var c = Math.floor(eventToMouseX(event, canvas) / tileSize); + // since the canvas is centered, the bounding client rect can be half-pixel aligned, + // resulting in slightly out-of-bounds mouse events. + r = clamp(r, 0, level.height); + c = clamp(c, 0, level.width); + return getLocation(level, r, c); } function eventToMouseX(event, canvas) { return event.clientX - canvas.getBoundingClientRect().left; } function eventToMouseY(event, canvas) { return event.clientY - canvas.getBoundingClientRect().top; } function selectAll() { - selectionStart = 0; - selectionEnd = level.map.length - 1; - setPaintBrushTileCode("select"); + selectionStart = 0; + selectionEnd = level.map.length - 1; + setPaintBrushTileCode("select"); } function setPaintBrushTileCode(tileCode) { - if (tileCode === "paste") { - // make sure we have something to paste - if (clipboardData == null) return; - } - if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { - // usually this means to fill in the selection - if (tileCode == null) { - // cancel selection - selectionStart = null; - selectionEnd = null; - return; - } - // fill in the selection - fillSelection(tileCode); - selectionStart = null; - selectionEnd = null; - return; - } - if (tileCode === SNAKE) { - if (paintBrushTileCode === SNAKE) { - // next snake color - paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; - } - } else if (tileCode === BLOCK) { - var blocks = getBlocks(); - if (paintBrushTileCode === BLOCK && blocks.length > 0) { - // cycle through block ids - blocks.sort(compareId); - if (paintBrushBlockId != null) { - (function() { - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id === paintBrushBlockId) { - i += 1; - if (i < blocks.length) { - // next block id - paintBrushBlockId = blocks[i].id; - } else { - // new block id - paintBrushBlockId = null; - } - return; + if (tileCode === "paste") { + // make sure we have something to paste + if (clipboardData == null) return; + } + if (paintBrushTileCode === "select" && tileCode !== "select" && selectionStart != null && selectionEnd != null) { + // usually this means to fill in the selection + if (tileCode == null) { + // cancel selection + selectionStart = null; + selectionEnd = null; + return; + } + // fill in the selection + fillSelection(tileCode); + selectionStart = null; + selectionEnd = null; + return; + } + if (tileCode === SNAKE) { + if (paintBrushTileCode === SNAKE) { + // next snake color + paintBrushSnakeColorIndex = (paintBrushSnakeColorIndex + 1) % snakeColors.length; + } + } else if (tileCode === BLOCK) { + var blocks = getBlocks(); + if (paintBrushTileCode === BLOCK && blocks.length > 0) { + // cycle through block ids + blocks.sort(compareId); + if (paintBrushBlockId != null) { + (function () { + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].id === paintBrushBlockId) { + i += 1; + if (i < blocks.length) { + // next block id + paintBrushBlockId = blocks[i].id; + } else { + // new block id + paintBrushBlockId = null; + } + return; + } + } + throw unreachable() + })(); + } else { + // first one + paintBrushBlockId = blocks[0].id; } - } - throw unreachable() - })(); - } else { - // first one - paintBrushBlockId = blocks[0].id; - } - } else { - // new block id - paintBrushBlockId = null; - } - } else if (tileCode == null) { - // escape - if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { - // stop editing this block, but keep the block brush selected - tileCode = BLOCK; - paintBrushBlockId = null; + } else { + // new block id + paintBrushBlockId = null; + } + } else if (tileCode == null) { + // escape + if (paintBrushTileCode === BLOCK && paintBrushBlockId != null) { + // stop editing this block, but keep the block brush selected + tileCode = BLOCK; + paintBrushBlockId = null; + } } - } - paintBrushTileCode = tileCode; - paintBrushTileCodeChanged(); + paintBrushTileCode = tileCode; + paintBrushTileCodeChanged(); } function paintBrushTileCodeChanged() { - paintButtonIdAndTileCodes.forEach(function(pair) { - var id = pair[0]; - var tileCode = pair[1]; - var backgroundStyle = ""; - var textColor = ""; - if (tileCode === paintBrushTileCode) { - if (tileCode === SNAKE) { - // show the color of the active snake in the color of the button - backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; - } else { - backgroundStyle = "linear-gradient(#4b91ff, #055ce4)"; - textColor = "white"; - } - } - document.getElementById(id).style.background = backgroundStyle; - document.getElementById(id).style.color = textColor; - }); + paintButtonIdAndTileCodes.forEach(function (pair) { + var id = pair[0]; + var tileCode = pair[1]; + var backgroundStyle = ""; + var textColor = ""; + if (tileCode === paintBrushTileCode) { + if (tileCode === SNAKE) { + // show the color of the active snake in the color of the button + backgroundStyle = snakeColors[paintBrushSnakeColorIndex]; + } else { + backgroundStyle = "linear-gradient(#4b91ff, #055ce4)"; + textColor = "white"; + } + } + document.getElementById(id).style.background = backgroundStyle; + document.getElementById(id).style.color = textColor; + }); - var isSelectionMode = paintBrushTileCode === "select"; - ["cutButton", "copyButton"].forEach(function (id) { - document.getElementById(id).disabled = !isSelectionMode; - }); - document.getElementById("pasteButton").disabled = clipboardData == null; + var isSelectionMode = paintBrushTileCode === "select"; + ["cutButton", "copyButton"].forEach(function (id) { + document.getElementById(id).disabled = !isSelectionMode; + }); + document.getElementById("pasteButton").disabled = clipboardData == null; - render(); + render(); } function cutSelection() { - copySelection(); - fillSelection(SPACE); - render(); + copySelection(); + fillSelection(SPACE); + render(); } function copySelection() { - var selectedLocations = getSelectedLocations(); - if (selectedLocations.length === 0) return; - var selectedObjects = []; - selectedLocations.forEach(function(location) { - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(selectedObjects, object); - }); - setClipboardData({ - level: JSON.parse(JSON.stringify(level)), - selectedLocations: selectedLocations, - selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), - }); + var selectedLocations = getSelectedLocations(); + if (selectedLocations.length === 0) return; + var selectedObjects = []; + selectedLocations.forEach(function (location) { + var object = findObjectAtLocation(location); + if (object != null) addIfNotPresent(selectedObjects, object); + }); + setClipboardData({ + level: JSON.parse(JSON.stringify(level)), + selectedLocations: selectedLocations, + selectedObjects: JSON.parse(JSON.stringify(selectedObjects)), + }); } function setClipboardData(data) { - // find the center - var minR = Infinity; - var maxR = -Infinity; - var minC = Infinity; - var maxC = -Infinity; - data.selectedLocations.forEach(function(location) { - var rowcol = getRowcol(data.level, location); - if (rowcol.r < minR) minR = rowcol.r; - if (rowcol.r > maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var offsetR = Math.floor((minR + maxR) / 2); - var offsetC = Math.floor((minC + maxC) / 2); - - clipboardData = data; - clipboardOffsetRowcol = {r:offsetR, c:offsetC}; - paintBrushTileCodeChanged(); + // find the center + var minR = Infinity; + var maxR = -Infinity; + var minC = Infinity; + var maxC = -Infinity; + data.selectedLocations.forEach(function (location) { + var rowcol = getRowcol(data.level, location); + if (rowcol.r < minR) minR = rowcol.r; + if (rowcol.r > maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var offsetR = Math.floor((minR + maxR) / 2); + var offsetC = Math.floor((minC + maxC) / 2); + + clipboardData = data; + clipboardOffsetRowcol = { r: offsetR, c: offsetC }; + paintBrushTileCodeChanged(); } function fillSelection(tileCode) { - var changeLog = []; - var locations = getSelectedLocations(); - locations.forEach(function(location) { - if (level.map[location] !== tileCode) { - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; - } - removeAnyObjectAtLocation(location, changeLog); - }); - pushUndo(uneditStuff, changeLog); + var changeLog = []; + var locations = getSelectedLocations(); + locations.forEach(function (location) { + if (level.map[location] !== tileCode) { + changeLog.push(["m", location, level.map[location], tileCode]); + level.map[location] = tileCode; + } + removeAnyObjectAtLocation(location, changeLog); + }); + pushUndo(uneditStuff, changeLog); } function getSelectedLocations() { - if (selectionStart == null || selectionEnd == null) return []; - var rowcol1 = getRowcol(level, selectionStart); - var rowcol2 = getRowcol(level, selectionEnd); - var r1 = rowcol1.r; - var c1 = rowcol1.c; - var r2 = rowcol2.r; - var c2 = rowcol2.c; - if (r2 < r1) { - var tmp = r1; - r1 = r2; - r2 = tmp; - } - if (c2 < c1) { - var tmp = c1; - c1 = c2; - c2 = tmp; - } - var objects = []; - var locations = []; - for (var r = r1; r <= r2; r++) { - for (var c = c1; c <= c2; c++) { - var location = getLocation(level, r, c); - locations.push(location); - var object = findObjectAtLocation(location); - if (object != null) addIfNotPresent(objects, object); + if (selectionStart == null || selectionEnd == null) return []; + var rowcol1 = getRowcol(level, selectionStart); + var rowcol2 = getRowcol(level, selectionEnd); + var r1 = rowcol1.r; + var c1 = rowcol1.c; + var r2 = rowcol2.r; + var c2 = rowcol2.c; + if (r2 < r1) { + var tmp = r1; + r1 = r2; + r2 = tmp; + } + if (c2 < c1) { + var tmp = c1; + c1 = c2; + c2 = tmp; + } + var objects = []; + var locations = []; + for (var r = r1; r <= r2; r++) { + for (var c = c1; c <= c2; c++) { + var location = getLocation(level, r, c); + locations.push(location); + var object = findObjectAtLocation(location); + if (object != null) addIfNotPresent(objects, object); + } } - } - // select the rest of any partially-selected objects - objects.forEach(function(object) { - object.locations.forEach(function(location) { - addIfNotPresent(locations, location); + // select the rest of any partially-selected objects + objects.forEach(function (object) { + object.locations.forEach(function (location) { + addIfNotPresent(locations, location); + }); }); - }); - return locations; + return locations; } function setHeight(newHeight, changeLog) { - if (newHeight < level.height) { - // crop - for (var r = newHeight; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - // also delete non-space tiles - paintTileAtLocation(location, SPACE, changeLog); - } - } - level.map.splice(newHeight * level.width); - } else { - // expand - for (var r = level.height; r < newHeight; r++) { - for (var c = 0; c < level.width; c++) { - level.map.push(SPACE); - } + if (newHeight < level.height) { + // crop + for (var r = newHeight; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + removeAnyObjectAtLocation(location, changeLog); + // also delete non-space tiles + paintTileAtLocation(location, SPACE, changeLog); + } + } + level.map.splice(newHeight * level.width); + } else { + // expand + for (var r = level.height; r < newHeight; r++) { + for (var c = 0; c < level.width; c++) { + level.map.push(SPACE); + } + } } - } - changeLog.push(["h", level.height, newHeight]); - level.height = newHeight; + changeLog.push(["h", level.height, newHeight]); + level.height = newHeight; } function setWidth(newWidth, changeLog) { - if (newWidth < level.width) { - // crop - for (var r = level.height - 1; r >= 0; r--) { - for (var c = level.width - 1; c >= newWidth; c--) { - var location = getLocation(level, r, c); - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, SPACE, changeLog); - level.map.splice(location, 1); - } - } - } else { - // expand - for (var r = level.height - 1; r >= 0; r--) { - var insertionPoint = level.width * (r + 1); - for (var c = level.width; c < newWidth; c++) { - // boy is this inefficient. ... YOLO! - level.map.splice(insertionPoint, 0, SPACE); - } + if (newWidth < level.width) { + // crop + for (var r = level.height - 1; r >= 0; r--) { + for (var c = level.width - 1; c >= newWidth; c--) { + var location = getLocation(level, r, c); + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, SPACE, changeLog); + level.map.splice(location, 1); + } + } + } else { + // expand + for (var r = level.height - 1; r >= 0; r--) { + var insertionPoint = level.width * (r + 1); + for (var c = level.width; c < newWidth; c++) { + // boy is this inefficient. ... YOLO! + level.map.splice(insertionPoint, 0, SPACE); + } + } } - } - var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); - level.objects.forEach(function(object) { - object.locations = object.locations.map(transformLocation); - }); + var transformLocation = makeScaleCoordinatesFunction(level.width, newWidth); + level.objects.forEach(function (object) { + object.locations = object.locations.map(transformLocation); + }); - changeLog.push(["w", level.width, newWidth]); - level.width = newWidth; + changeLog.push(["w", level.width, newWidth]); + level.width = newWidth; } function newSnake(color, location) { - var snakes = findSnakesOfColor(color); - snakes.sort(compareId); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id !== i * snakeColors.length + color) break; - } - return { - type: SNAKE, - id: i * snakeColors.length + color, - dead: false, - locations: [location], - }; + var snakes = findSnakesOfColor(color); + snakes.sort(compareId); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id !== i * snakeColors.length + color) break; + } + return { + type: SNAKE, + id: i * snakeColors.length + color, + dead: false, + locations: [location], + }; } function newBlock(location) { - var blocks = getBlocks(); - blocks.sort(compareId); - for (var i = 0; i < blocks.length; i++) { - if (blocks[i].id !== i) break; - } - return { - type: BLOCK, - id: i, - dead: false, // unused - locations: [location], - }; + var blocks = getBlocks(); + blocks.sort(compareId); + for (var i = 0; i < blocks.length; i++) { + if (blocks[i].id !== i) break; + } + return { + type: BLOCK, + id: i, + dead: false, // unused + locations: [location], + }; } function newFruit(location) { - var fruits = getObjectsOfType(FRUIT); - fruits.sort(compareId); - for (var i = 0; i < fruits.length; i++) { - if (fruits[i].id !== i) break; - } - return { - type: FRUIT, - id: i, - dead: false, // unused - locations: [location], - }; + var fruits = getObjectsOfType(FRUIT); + fruits.sort(compareId); + for (var i = 0; i < fruits.length; i++) { + if (fruits[i].id !== i) break; + } + return { + type: FRUIT, + id: i, + dead: false, // unused + locations: [location], + }; } function paintAtLocation(location, changeLog) { - if (typeof paintBrushTileCode === "number") { - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, paintBrushTileCode, changeLog); - } else if (paintBrushTileCode === "resize") { - var toRowcol = getRowcol(level, location); - var dr = toRowcol.r - resizeDragAnchorRowcol.r; - var dc = toRowcol.c - resizeDragAnchorRowcol.c; - resizeDragAnchorRowcol = toRowcol; - if (dr !== 0) setHeight(level.height + dr, changeLog); - if (dc !== 0) setWidth(level.width + dc, changeLog); - } else if (paintBrushTileCode === "select") { - selectionEnd = location; - } else if (paintBrushTileCode === "paste") { - var hoverRowcol = getRowcol(level, location); - var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); - pastedData.selectedLocations.forEach(function(location) { - var tileCode = pastedData.level.map[location]; - removeAnyObjectAtLocation(location, changeLog); - paintTileAtLocation(location, tileCode, changeLog); - }); - pastedData.selectedObjects.forEach(function(object) { - // refresh the ids so there are no collisions. - if (object.type === SNAKE) { - object.id = newSnake(object.id % snakeColors.length).id; - } else if (object.type === BLOCK) { - object.id = newBlock().id; - } else if (object.type === FRUIT) { - object.id = newFruit().id; - } else throw unreachable(); - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - }); - } else if (paintBrushTileCode === SNAKE) { - var oldSnakeSerialization = serializeObjectState(paintBrushObject); - if (paintBrushObject != null) { - // keep dragging - if (paintBrushObject.locations[0] === location) return; // we just did that - // watch out for self-intersection - var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); - if (selfIntersectionIndex !== -1) { - // truncate from here back - paintBrushObject.locations.splice(selfIntersectionIndex); - } - } + if (typeof paintBrushTileCode === "number") { + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, paintBrushTileCode, changeLog); + } else if (paintBrushTileCode === "resize") { + var toRowcol = getRowcol(level, location); + var dr = toRowcol.r - resizeDragAnchorRowcol.r; + var dc = toRowcol.c - resizeDragAnchorRowcol.c; + resizeDragAnchorRowcol = toRowcol; + if (dr !== 0) setHeight(level.height + dr, changeLog); + if (dc !== 0) setWidth(level.width + dc, changeLog); + } else if (paintBrushTileCode === "select") { + selectionEnd = location; + } else if (paintBrushTileCode === "paste") { + var hoverRowcol = getRowcol(level, location); + var pastedData = previewPaste(hoverRowcol.r, hoverRowcol.c); + pastedData.selectedLocations.forEach(function (location) { + var tileCode = pastedData.level.map[location]; + removeAnyObjectAtLocation(location, changeLog); + paintTileAtLocation(location, tileCode, changeLog); + }); + pastedData.selectedObjects.forEach(function (object) { + // refresh the ids so there are no collisions. + if (object.type === SNAKE) { + object.id = newSnake(object.id % snakeColors.length).id; + } else if (object.type === BLOCK) { + object.id = newBlock().id; + } else if (object.type === FRUIT) { + object.id = newFruit().id; + } else throw unreachable(); + level.objects.push(object); + changeLog.push([object.type, object.id, [0, []], serializeObjectState(object)]); + }); + } else if (paintBrushTileCode === SNAKE) { + var oldSnakeSerialization = serializeObjectState(paintBrushObject); + if (paintBrushObject != null) { + // keep dragging + if (paintBrushObject.locations[0] === location) return; // we just did that + // watch out for self-intersection + var selfIntersectionIndex = paintBrushObject.locations.indexOf(location); + if (selfIntersectionIndex !== -1) { + // truncate from here back + paintBrushObject.locations.splice(selfIntersectionIndex); + } + } - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - if (paintBrushObject == null) { - var thereWereNoSnakes = countSnakes() === 0; - paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); - level.objects.push(paintBrushObject); - if (thereWereNoSnakes) activateAnySnakePlease(); - } else { - // extend le snake - paintBrushObject.locations.unshift(location); - } - changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); - } else if (paintBrushTileCode === BLOCK) { - var objectHere = findObjectAtLocation(location); - if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { - // just start editing this block - paintBrushBlockId = objectHere.id; - } else { - // make a change - // make sure there's space behind us - paintTileAtLocation(location, SPACE, changeLog); - var thisBlock = null; - if (paintBrushBlockId != null) { - thisBlock = findBlockById(paintBrushBlockId); - } - var oldBlockSerialization = serializeObjectState(thisBlock); - if (thisBlock == null) { - // create new block + // make sure there's space behind us + paintTileAtLocation(location, SPACE, changeLog); removeAnyObjectAtLocation(location, changeLog); - thisBlock = newBlock(location); - level.objects.push(thisBlock); - paintBrushBlockId = thisBlock.id; - } else { - var existingIndex = thisBlock.locations.indexOf(location); - if (existingIndex !== -1) { - // reclicking part of this object means to delete just part of it. - if (thisBlock.locations.length === 1) { - // goodbye - removeObject(thisBlock, changeLog); - paintBrushBlockId = null; - } else { - thisBlock.locations.splice(existingIndex, 1); - } + if (paintBrushObject == null) { + var thereWereNoSnakes = countSnakes() === 0; + paintBrushObject = newSnake(paintBrushSnakeColorIndex, location); + level.objects.push(paintBrushObject); + if (thereWereNoSnakes) activateAnySnakePlease(); } else { - // add a tile to the block - removeAnyObjectAtLocation(location, changeLog); - thisBlock.locations.push(location); + // extend le snake + paintBrushObject.locations.unshift(location); } - } - changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); - delete blockSupportRenderCache[thisBlock.id]; - } - } else if (paintBrushTileCode === FRUIT) { - paintTileAtLocation(location, SPACE, changeLog); - removeAnyObjectAtLocation(location, changeLog); - var object = newFruit(location) - level.objects.push(object); - changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); - } else throw unreachable(); - render(); + changeLog.push([paintBrushObject.type, paintBrushObject.id, oldSnakeSerialization, serializeObjectState(paintBrushObject)]); + } else if (paintBrushTileCode === BLOCK) { + var objectHere = findObjectAtLocation(location); + if (paintBrushBlockId == null && objectHere != null && objectHere.type === BLOCK) { + // just start editing this block + paintBrushBlockId = objectHere.id; + } else { + // make a change + // make sure there's space behind us + paintTileAtLocation(location, SPACE, changeLog); + var thisBlock = null; + if (paintBrushBlockId != null) { + thisBlock = findBlockById(paintBrushBlockId); + } + var oldBlockSerialization = serializeObjectState(thisBlock); + if (thisBlock == null) { + // create new block + removeAnyObjectAtLocation(location, changeLog); + thisBlock = newBlock(location); + level.objects.push(thisBlock); + paintBrushBlockId = thisBlock.id; + } else { + var existingIndex = thisBlock.locations.indexOf(location); + if (existingIndex !== -1) { + // reclicking part of this object means to delete just part of it. + if (thisBlock.locations.length === 1) { + // goodbye + removeObject(thisBlock, changeLog); + paintBrushBlockId = null; + } else { + thisBlock.locations.splice(existingIndex, 1); + } + } else { + // add a tile to the block + removeAnyObjectAtLocation(location, changeLog); + thisBlock.locations.push(location); + } + } + changeLog.push([thisBlock.type, thisBlock.id, oldBlockSerialization, serializeObjectState(thisBlock)]); + delete blockSupportRenderCache[thisBlock.id]; + } + } else if (paintBrushTileCode === FRUIT) { + paintTileAtLocation(location, SPACE, changeLog); + removeAnyObjectAtLocation(location, changeLog); + var object = newFruit(location) + level.objects.push(object); + changeLog.push([object.type, object.id, serializeObjectState(null), serializeObjectState(object)]); + } else throw unreachable(); + render(); } function paintTileAtLocation(location, tileCode, changeLog) { - if (level.map[location] === tileCode) return; - changeLog.push(["m", location, level.map[location], tileCode]); - level.map[location] = tileCode; + if (level.map[location] === tileCode) return; + changeLog.push(["m", location, level.map[location], tileCode]); + level.map[location] = tileCode; } function pushUndo(undoStuff, changeLog) { - // changeLog = [ - // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], - // // player input for snake 0, dr:-1, dc:0. has no effect on state. - // // "i" is always the first change in normal player movement. - // // if a changeLog does not start with "i", then it is an editor action. - // // animationQueue and freshlyRemovedAnimatedObjects - // // are used for animating re-move. - // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 - // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] - // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] - // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] - // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] - // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. - // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. - // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. - // 10, // the last change is always a declaration of the final width of the map. - // ]; - reduceChangeLog(changeLog); - if (changeLog.length === 0) return; - changeLog.push(level.width); - undoStuff.undoStack.push(changeLog); - undoStuff.redoStack = []; - paradoxes = []; - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; - - undoStuffChanged(undoStuff); + // changeLog = [ + // ["i", 0, -1, 0, animationQueue, freshlyRemovedAnimatedObjects], + // // player input for snake 0, dr:-1, dc:0. has no effect on state. + // // "i" is always the first change in normal player movement. + // // if a changeLog does not start with "i", then it is an editor action. + // // animationQueue and freshlyRemovedAnimatedObjects + // // are used for animating re-move. + // ["m", 21, 0, 1], // map at location 23 changed from 0 to 1 + // ["s", 0, [false, [1,2]], [false, [2,3]]], // snake id 0 moved from alive at [1, 2] to alive at [2, 3] + // ["s", 1, [false, [11,12]], [true, [12,13]]], // snake id 1 moved from alive at [11, 12] to dead at [12, 13] + // ["b", 1, [false, [20,30]], [false, []]], // block id 1 was deleted from location [20, 30] + // ["f", 0, [false, [40]], [false, []]], // fruit id 0 was deleted from location [40] + // ["h", 25, 10], // height changed from 25 to 10. all cropped tiles are guaranteed to be SPACE. + // ["w", 8, 10], // width changed from 8 to 10. a change in the coordinate system. + // ["m", 23, 2, 0], // map at location 23 changed from 2 to 0 in the new coordinate system. + // 10, // the last change is always a declaration of the final width of the map. + // ]; + reduceChangeLog(changeLog); + if (changeLog.length === 0) return; + changeLog.push(level.width); + undoStuff.undoStack.push(changeLog); + undoStuff.redoStack = []; + paradoxes = []; + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; + + undoStuffChanged(undoStuff); } function reduceChangeLog(changeLog) { - for (var i = 0; i < changeLog.length - 1; i++) { - var change = changeLog[i]; - if (change[0] === "i") { - continue; // don't reduce player input - } else if (change[0] === "h") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "h") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "w") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "w") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "w") { - // combine - change[2] = otherChange[2]; - changeLog.splice(j, 1); - j--; - continue; - } else if (otherChange[0] === "h") { - continue; // no interaction between height and width - } else break; // no more reduction possible - } - if (change[1] === change[2]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === "m") { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === "m" && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (change[2] === change[3]) { - // no change - changeLog.splice(i, 1); - i--; - } - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { - for (var j = i + 1; j < changeLog.length; j++) { - var otherChange = changeLog[j]; - if (otherChange[0] === change[0] && otherChange[1] === change[1]) { - // combine - change[3] = otherChange[3]; - changeLog.splice(j, 1); - j--; - } else if (otherChange[0] === "w" || otherChange[0] === "h") { - break; // can't reduce accros resizes - } - } - if (deepEquals(change[2], change[3])) { - // no change - changeLog.splice(i, 1); - i--; - } - } else throw unreachable(); - } + for (var i = 0; i < changeLog.length - 1; i++) { + var change = changeLog[i]; + if (change[0] === "i") { + continue; // don't reduce player input + } else if (change[0] === "h") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "h") { + // combine + change[2] = otherChange[2]; + changeLog.splice(j, 1); + j--; + continue; + } else if (otherChange[0] === "w") { + continue; // no interaction between height and width + } else break; // no more reduction possible + } + if (change[1] === change[2]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === "w") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "w") { + // combine + change[2] = otherChange[2]; + changeLog.splice(j, 1); + j--; + continue; + } else if (otherChange[0] === "h") { + continue; // no interaction between height and width + } else break; // no more reduction possible + } + if (change[1] === change[2]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === "m") { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === "m" && otherChange[1] === change[1]) { + // combine + change[3] = otherChange[3]; + changeLog.splice(j, 1); + j--; + } else if (otherChange[0] === "w" || otherChange[0] === "h") { + break; // can't reduce accros resizes + } + } + if (change[2] === change[3]) { + // no change + changeLog.splice(i, 1); + i--; + } + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { + for (var j = i + 1; j < changeLog.length; j++) { + var otherChange = changeLog[j]; + if (otherChange[0] === change[0] && otherChange[1] === change[1]) { + // combine + change[3] = otherChange[3]; + changeLog.splice(j, 1); + j--; + } else if (otherChange[0] === "w" || otherChange[0] === "h") { + break; // can't reduce accros resizes + } + } + if (deepEquals(change[2], change[3])) { + // no change + changeLog.splice(i, 1); + i--; + } + } else throw unreachable(); + } } function undo(undoStuff) { - if (undoStuff.undoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - undoOneFrame(undoStuff); - undoStuffChanged(undoStuff); + if (undoStuff.undoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + undoOneFrame(undoStuff); + undoStuffChanged(undoStuff); } function reset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.undoStack.length > 0) { - undoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + while (undoStuff.undoStack.length > 0) { + undoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); } function undoOneFrame(undoStuff) { - var doThis = undoStuff.undoStack.pop(); - var redoChangeLog = []; - undoChanges(doThis, redoChangeLog); - if (redoChangeLog.length > 0) { - redoChangeLog.push(level.width); - undoStuff.redoStack.push(redoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; + var doThis = undoStuff.undoStack.pop(); + var redoChangeLog = []; + undoChanges(doThis, redoChangeLog); + if (redoChangeLog.length > 0) { + redoChangeLog.push(level.width); + undoStuff.redoStack.push(redoChangeLog); + } + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; } function redo(undoStuff) { - if (undoStuff.redoStack.length === 0) return; // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - redoOneFrame(undoStuff); - undoStuffChanged(undoStuff); + if (undoStuff.redoStack.length === 0) return; // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + redoOneFrame(undoStuff); + undoStuffChanged(undoStuff); } function redoAll(undoStuff) { - //blockSupportRenderCache = []; //didn't work - cs = true; - if (undoStuff.redoStack.length === 0) render(); // already at the beginning - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - - while (undoStuff.redoStack.length > 0) { - redoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); - - if(checkResult) { - cr = true; - render(); - } - else { - render(); - } + //blockSupportRenderCache = []; //didn't work + cs = true; + if (undoStuff.redoStack.length === 0) render(); // already at the beginning + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + + while (undoStuff.redoStack.length > 0) { + redoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); + + if (checkResult) { + cr = true; + render(); + } + else { + render(); + } } function copyToClipboard(text) { var dummy = document.createElement("textarea"); @@ -1195,189 +1195,189 @@ function copyToClipboard(text) { document.body.removeChild(dummy); } function unreset(undoStuff) { - animationQueue = []; - animationQueueCursor = 0; - paradoxes = []; - while (undoStuff.redoStack.length > 0) { - redoOneFrame(undoStuff); - } - undoStuffChanged(undoStuff); + animationQueue = []; + animationQueueCursor = 0; + paradoxes = []; + while (undoStuff.redoStack.length > 0) { + redoOneFrame(undoStuff); + } + undoStuffChanged(undoStuff); - // don't animate the last frame - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; + // don't animate the last frame + animationQueue = []; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = []; } function redoOneFrame(undoStuff) { - var doThis = undoStuff.redoStack.pop(); - var undoChangeLog = []; - undoChanges(doThis, undoChangeLog); - if (undoChangeLog.length > 0) { - undoChangeLog.push(level.width); - undoStuff.undoStack.push(undoChangeLog); - } - - if (undoStuff === uneditStuff) editorHasBeenTouched = true; + var doThis = undoStuff.redoStack.pop(); + var undoChangeLog = []; + undoChanges(doThis, undoChangeLog); + if (undoChangeLog.length > 0) { + undoChangeLog.push(level.width); + undoStuff.undoStack.push(undoChangeLog); + } + + if (undoStuff === uneditStuff) editorHasBeenTouched = true; } function undoChanges(changes, changeLog) { - var widthContext = changes.pop(); - var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); - for (var i = changes.length - 1; i >= 0; i--) { - var paradoxDescription = undoChange(changes[i]); - if (paradoxDescription != null) paradoxes.push(paradoxDescription); - } - - var lastChange = changes[changes.length - 1]; - if (lastChange[0] === "i") { - // replay animation - animationQueue = lastChange[4]; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = lastChange[5]; - animationStart = new Date().getTime(); - } - - function undoChange(change) { - // note: everything here is going backwards: to -> from - if (change[0] === "i") { - // no state change, but preserve the intention. - changeLog.push(change); - return null; - } else if (change[0] === "h") { - // change height - var fromHeight = change[1]; - var toHeight = change[2]; - if (level.height !== toHeight) return "Impossible"; - setHeight(fromHeight, changeLog); - } else if (change[0] === "w") { - // change width - var fromWidth = change[1]; - var toWidth = change[2]; - if (level.width !== toWidth) return "Impossible"; - setWidth(fromWidth, changeLog); - } else if (change[0] === "m") { - // change map tile - var location = transformLocation(change[1]); - var fromTileCode = change[2]; - var toTileCode = change[3]; - if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; - if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; - paintTileAtLocation(location, fromTileCode, changeLog); - } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { - // change object - var type = change[0]; - var id = change[1]; - var fromDead = change[2][0]; - var toDead = change[3][0]; - var fromLocations = change[2][1].map(transformLocation); - var toLocations = change[3][1].map(transformLocation); - if (fromLocations.filter(function(location) { return location >= level.map.length; }).length > 0) { - return "Can't move " + describe(type, id) + " out of bounds"; - } - var object = findObjectOfTypeAndId(type, id); - if (toLocations.length !== 0) { - // should exist at this location - if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; - if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; - if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; - // doit - if (fromLocations.length !== 0) { - var oldState = serializeObjectState(object); - object.locations = fromLocations; - object.dead = fromDead; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - } else { - removeObject(object, changeLog); - } - } else { - // shouldn't exist - if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; - // doit - object = { - type: type, - id: id, - dead: fromDead, - locations: fromLocations, - }; - level.objects.push(object); - changeLog.push([object.type, object.id, [0,[]], serializeObjectState(object)]); - } - } else throw unreachable(); - } + var widthContext = changes.pop(); + var transformLocation = widthContext === level.width ? identityFunction : makeScaleCoordinatesFunction(widthContext, level.width); + for (var i = changes.length - 1; i >= 0; i--) { + var paradoxDescription = undoChange(changes[i]); + if (paradoxDescription != null) paradoxes.push(paradoxDescription); + } + + var lastChange = changes[changes.length - 1]; + if (lastChange[0] === "i") { + // replay animation + animationQueue = lastChange[4]; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = lastChange[5]; + animationStart = new Date().getTime(); + } + + function undoChange(change) { + // note: everything here is going backwards: to -> from + if (change[0] === "i") { + // no state change, but preserve the intention. + changeLog.push(change); + return null; + } else if (change[0] === "h") { + // change height + var fromHeight = change[1]; + var toHeight = change[2]; + if (level.height !== toHeight) return "Impossible"; + setHeight(fromHeight, changeLog); + } else if (change[0] === "w") { + // change width + var fromWidth = change[1]; + var toWidth = change[2]; + if (level.width !== toWidth) return "Impossible"; + setWidth(fromWidth, changeLog); + } else if (change[0] === "m") { + // change map tile + var location = transformLocation(change[1]); + var fromTileCode = change[2]; + var toTileCode = change[3]; + if (location >= level.map.length) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " out of bounds"; + if (level.map[location] !== toTileCode) return "Can't turn " + describe(toTileCode) + " into " + describe(fromTileCode) + " because there's " + describe(level.map[location]) + " there now"; + paintTileAtLocation(location, fromTileCode, changeLog); + } else if (change[0] === SNAKE || change[0] === BLOCK || change[0] === FRUIT) { + // change object + var type = change[0]; + var id = change[1]; + var fromDead = change[2][0]; + var toDead = change[3][0]; + var fromLocations = change[2][1].map(transformLocation); + var toLocations = change[3][1].map(transformLocation); + if (fromLocations.filter(function (location) { return location >= level.map.length; }).length > 0) { + return "Can't move " + describe(type, id) + " out of bounds"; + } + var object = findObjectOfTypeAndId(type, id); + if (toLocations.length !== 0) { + // should exist at this location + if (object == null) return "Can't move " + describe(type, id) + " because it doesn't exit"; + if (!deepEquals(object.locations, toLocations)) return "Can't move " + describe(object) + " because it's in the wrong place"; + if (object.dead !== toDead) return "Can't move " + describe(object) + " because it's alive/dead state doesn't match"; + // doit + if (fromLocations.length !== 0) { + var oldState = serializeObjectState(object); + object.locations = fromLocations; + object.dead = fromDead; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + } else { + removeObject(object, changeLog); + } + } else { + // shouldn't exist + if (object != null) return "Can't create " + describe(type, id) + " because it already exists"; + // doit + object = { + type: type, + id: id, + dead: fromDead, + locations: fromLocations, + }; + level.objects.push(object); + changeLog.push([object.type, object.id, [0, []], serializeObjectState(object)]); + } + } else throw unreachable(); + } } function describe(arg1, arg2) { - // describe(0) -> "Space" - // describe(SNAKE, 0) -> "Snake 0 (Red)" - // describe(object) -> "Snake 0 (Red)" - // describe(BLOCK, 1) -> "Block 1" - // describe(FRUIT) -> "Fruit" - if (typeof arg1 === "number") { - switch (arg1) { - case SPACE: return "Space"; - case WALL: return "a Wall"; - case SPIKE: return "Spikes"; - case EXIT: return "an Exit"; - case PORTAL: return "a Portal"; - case PLATFORM: return "a Platform"; - case WOODPLATFORM: return "a Wooden Platform"; - case ONEWAYWALLU: return "a One Way Wall (facing U)"; - case ONEWAYWALLD: return "a One Way Wall (facing D)"; - case ONEWAYWALLL: return "a One Way Wall (facing L)"; - case ONEWAYWALLR: return "a One Way Wall (facing R)"; - case CLOSEDLIFT: return "a Closed Lift"; - case OPENLIFT: return "an Open Lift"; - case CLOUD: return "a Cloud"; - case BUBBLE: return "a Bubble"; - case LAVA: return "Lava"; - case WATER: return "Water"; - default: throw unreachable(); + // describe(0) -> "Space" + // describe(SNAKE, 0) -> "Snake 0 (Red)" + // describe(object) -> "Snake 0 (Red)" + // describe(BLOCK, 1) -> "Block 1" + // describe(FRUIT) -> "Fruit" + if (typeof arg1 === "number") { + switch (arg1) { + case SPACE: return "Space"; + case WALL: return "a Wall"; + case SPIKE: return "Spikes"; + case EXIT: return "an Exit"; + case PORTAL: return "a Portal"; + case PLATFORM: return "a Platform"; + case WOODPLATFORM: return "a Wooden Platform"; + case ONEWAYWALLU: return "a One Way Wall (facing U)"; + case ONEWAYWALLD: return "a One Way Wall (facing D)"; + case ONEWAYWALLL: return "a One Way Wall (facing L)"; + case ONEWAYWALLR: return "a One Way Wall (facing R)"; + case CLOSEDLIFT: return "a Closed Lift"; + case OPENLIFT: return "an Open Lift"; + case CLOUD: return "a Cloud"; + case BUBBLE: return "a Bubble"; + case LAVA: return "Lava"; + case WATER: return "Water"; + default: throw unreachable(); + } + } + if (arg1 === SNAKE) { + var color = (function () { + switch (snakeColors[arg2 % snakeColors.length]) { + case "#fd0c0b": return " (Red)"; + case "#18d11f": return " (Green)"; + case "#004cff": return " (Blue)"; + case "#fdc122": return " (Yellow)"; + default: throw unreachable(); + } + })(); + return "Snake " + arg2 + color; + } + if (arg1 === BLOCK) { + return "Block " + arg2; + } + if (arg1 === FRUIT) { + return "Fruit"; } - } - if (arg1 === SNAKE) { - var color = (function() { - switch (snakeColors[arg2 % snakeColors.length]) { - case "#fd0c0b": return " (Red)"; - case "#18d11f": return " (Green)"; - case "#004cff": return " (Blue)"; - case "#fdc122": return " (Yellow)"; - default: throw unreachable(); - } - })(); - return "Snake " + arg2 + color; - } - if (arg1 === BLOCK) { - return "Block " + arg2; - } - if (arg1 === FRUIT) { - return "Fruit"; - } - if (typeof arg1 === "object") return describe(arg1.type, arg1.id); - throw unreachable(); + if (typeof arg1 === "object") return describe(arg1.type, arg1.id); + throw unreachable(); } function undoStuffChanged(undoStuff) { - var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; - document.getElementById(undoStuff.spanId).textContent = movesText; - document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; - document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; - - // render paradox display - var uniqueParadoxes = []; - var paradoxCounts = []; - paradoxes.forEach(function(paradoxDescription) { - var index = uniqueParadoxes.indexOf(paradoxDescription); - if (index !== -1) { - paradoxCounts[index] += 1; - } else { - uniqueParadoxes.push(paradoxDescription); - paradoxCounts.push(1); - } - }); + var movesText = undoStuff.undoStack.length + "+" + undoStuff.redoStack.length; + document.getElementById(undoStuff.spanId).textContent = movesText; + document.getElementById(undoStuff.undoButtonId).disabled = undoStuff.undoStack.length === 0; + document.getElementById(undoStuff.redoButtonId).disabled = undoStuff.redoStack.length === 0; + + // render paradox display + var uniqueParadoxes = []; + var paradoxCounts = []; + paradoxes.forEach(function (paradoxDescription) { + var index = uniqueParadoxes.indexOf(paradoxDescription); + if (index !== -1) { + paradoxCounts[index] += 1; + } else { + uniqueParadoxes.push(paradoxDescription); + paradoxCounts.push(1); + } + }); - updateDirtyState(); + updateDirtyState(); - if (unmoveStuff.redoStack.length === 0) { - document.getElementById("removeButton").classList.remove("click-me"); - } + if (unmoveStuff.redoStack.length === 0) { + document.getElementById("removeButton").classList.remove("click-me"); + } } var CLEAN_NO_TIMELINES = 0; @@ -1387,60 +1387,60 @@ var EDITOR_DIRTY = 3; var dirtyState = CLEAN_NO_TIMELINES; var editorHasBeenTouched = false; function updateDirtyState() { - if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { - dirtyState = EDITOR_DIRTY; - } else if (unmoveStuff.undoStack.length > 0) { - dirtyState = REPLAY_DIRTY; - } else if (unmoveStuff.redoStack.length > 0) { - dirtyState = CLEAN_WITH_REDO; - } else { - dirtyState = CLEAN_NO_TIMELINES; - } - - var saveLevelButton = document.getElementById("saveLevelButton"); - // the save button clears your timelines - saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; - if (dirtyState >= EDITOR_DIRTY) { - // you should save - saveLevelButton.classList.add("click-me"); - } else { - saveLevelButton.classList.remove("click-me"); - } + if (haveCheatcodesBeenUsed() || editorHasBeenTouched) { + dirtyState = EDITOR_DIRTY; + } else if (unmoveStuff.undoStack.length > 0) { + dirtyState = REPLAY_DIRTY; + } else if (unmoveStuff.redoStack.length > 0) { + dirtyState = CLEAN_WITH_REDO; + } else { + dirtyState = CLEAN_NO_TIMELINES; + } + + var saveLevelButton = document.getElementById("saveLevelButton"); + // the save button clears your timelines + saveLevelButton.disabled = dirtyState === CLEAN_NO_TIMELINES; + if (dirtyState >= EDITOR_DIRTY) { + // you should save + saveLevelButton.classList.add("click-me"); + } else { + saveLevelButton.classList.remove("click-me"); + } } function haveCheatcodesBeenUsed() { - return !unmoveStuff.undoStack.every(function(changeLog) { - // normal movement always starts with "i". - return changeLog[0][0] === "i"; - }); + return !unmoveStuff.undoStack.every(function (changeLog) { + // normal movement always starts with "i". + return changeLog[0][0] === "i"; + }); } var persistentState = { - showEditor: false, + showEditor: false, }; function savePersistentState() { - localStorage.snakefall = JSON.stringify(persistentState); + localStorage.snakefall = JSON.stringify(persistentState); } function loadPersistentState() { - try { - persistentState = JSON.parse(localStorage.snakefall); - } catch (e) { - } - persistentState.showEditor = !!persistentState.showEditor; - showEditorChanged(); + try { + persistentState = JSON.parse(localStorage.snakefall); + } catch (e) { + } + persistentState.showEditor = !!persistentState.showEditor; + showEditorChanged(); } var isGravityEnabled = true; function isGravity() { - return isGravityEnabled || !persistentState.showEditor; + return isGravityEnabled || !persistentState.showEditor; } var isCollisionEnabled = true; function isCollision() { - return isCollisionEnabled || !persistentState.showEditor; + return isCollisionEnabled || !persistentState.showEditor; } function isAnyCheatcodeEnabled() { - return persistentState.showEditor && ( - !isGravityEnabled || !isCollisionEnabled - ); + return persistentState.showEditor && ( + !isGravityEnabled || !isCollisionEnabled + ); } var themeName = "Spring"; //Gooby var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle, experimentalColors; @@ -1455,31 +1455,31 @@ var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; var snakeColors2 = ["#f00", "#0f0", "#00f", "#ff0"]; var snakeColors3 = ["#BA145C", "#E91624", "#F75802", "#FEFE28"]; -var fruitColors1 = ["#ff0066","#ff36a6","#ff6b1f","#ff9900","#ff2600"]; -var fruitColors2 = ["black","black","black","black","black"]; +var fruitColors1 = ["#ff0066", "#ff36a6", "#ff6b1f", "#ff9900", "#ff2600"]; +var fruitColors2 = ["black", "black", "black", "black", "black"]; var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spike, support, box, bolt var spikeColors2 = ["gray", "black", "white", "black"]; var spikeColors3 = ["#333", "#333", "#333", "#777"]; var blockColors1 = [ - ["#de5a6d","#fa65dd","#c367e3","#9c62fa","#625ff0"], - ["#853641","#963c84","#753d88","#5d3a96","#3a3990"] + ["#de5a6d", "#fa65dd", "#c367e3", "#9c62fa", "#625ff0"], + ["#853641", "#963c84", "#753d88", "#5d3a96", "#3a3990"] ]; var blockColors2 = [ ["#999"], ["#999"] ]; var blockColors3 = [ - ["#de7913","#7d46a0","#39868b","#41ccc2","#ded800"], - ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] + ["#de7913", "#7d46a0", "#39868b", "#41ccc2", "#ded800"], + ["#8d4d0c", "#532f6a", "#2c686d", "#207973", "#999400"] ]; var blockColors4 = [ ["#150612", "#a52e8b", "#990077", "#d917af", "#4d003c"], - ["#8d4d0c","#532f6a","#2c686d","#207973","#999400"] + ["#8d4d0c", "#532f6a", "#2c686d", "#207973", "#999400"] ]; -var fontSize = tileSize*5; +var fontSize = tileSize * 5; var textStyle1 = ["" + fontSize + "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose var textStyle2 = ["" + fontSize + "px Impact", "#5702c6", "#ff0098"]; var textStyle3 = ["" + fontSize + "px Impact", "#BA145C", "#F75802"]; @@ -1491,527 +1491,523 @@ var experimentalColors2 = ["white", "#FEFE28"]; var themeCounter = 0; var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor, textStyle, experimentalColors - //["sky",], - ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], - ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], - ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], - ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] + //["sky",], + ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], + ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], + ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], + ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], + ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], + ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] ]; function showEditorChanged() { - document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; - ["editorDiv", "editorPane"].forEach(function(id) { - document.getElementById(id).style.display = persistentState.showEditor ? "none" : "none"; - }); + document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; + ["editorDiv", "editorPane"].forEach(function (id) { + document.getElementById(id).style.display = persistentState.showEditor ? "none" : "none"; + }); - render(); + render(); } function move(dr, dc) { - if (!isAlive()) return; - animationQueue = []; - animationQueueCursor = 0; - freshlyRemovedAnimatedObjects = []; - animationStart = new Date().getTime(); - var activeSnake = findActiveSnake(); - var headRowcol = getRowcol(level, activeSnake.locations[0]); - var newRowcol = {r:headRowcol.r + dr, c:headRowcol.c + dc}; - if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; - var newLocation = getLocation(level, newRowcol.r, newRowcol.c); - var changeLog = []; - - // The changeLog for a player movement starts with the input - // when playing normally. - if (!isAnyCheatcodeEnabled()) { - changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); - } - - var ate = false; - var pushedObjects = []; - - //track ClosedLifts that had objects on them - var occupiedClosedLift = getOccupiedClosedLiftLocations(); - - if (isCollision()) { - var newTile = level.map[newLocation]; - if (newTile === BUBBLE || newTile === CLOUD) - paintTileAtLocation(newLocation, SPACE, changeLog); - else if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile - var otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { - if (otherObject === activeSnake) return; // can't push yourself - if (otherObject.type === FRUIT) { - // eat - removeObject(otherObject, changeLog); - ate = true; - } else if (isTileCodeAir(activeSnake, null, newTile, dr, dc)) { - otherObject = findObjectAtLocation(newLocation); - if (otherObject != null) { + if (!isAlive()) return; + animationQueue = []; + animationQueueCursor = 0; + freshlyRemovedAnimatedObjects = []; + animationStart = new Date().getTime(); + var activeSnake = findActiveSnake(); + var headRowcol = getRowcol(level, activeSnake.locations[0]); + var newRowcol = { r: headRowcol.r + dr, c: headRowcol.c + dc }; + if (!isInBounds(level, newRowcol.r, newRowcol.c)) return; + var newLocation = getLocation(level, newRowcol.r, newRowcol.c); + var changeLog = []; + + // The changeLog for a player movement starts with the input + // when playing normally. + if (!isAnyCheatcodeEnabled()) { + changeLog.push(["i", activeSnake.id, dr, dc, animationQueue, freshlyRemovedAnimatedObjects]); + } + + var ate = false; + var pushedObjects = []; + + //track ClosedLifts that had objects on them + var occupiedClosedLift = getOccupiedClosedLiftLocations(); + + if (isCollision()) { + var newTile = level.map[newLocation]; + if (newTile === BUBBLE || newTile === CLOUD) + paintTileAtLocation(newLocation, SPACE, changeLog); + else if (!isTileCodeAir(activeSnake, null, newTile, dr, dc)) return; // can't go through that tile + var otherObject = findObjectAtLocation(newLocation); + if (otherObject != null) { if (otherObject === activeSnake) return; // can't push yourself - // push objects - if (!checkMovement(activeSnake, otherObject, dr, dc, pushedObjects)) return false; - } - } else return; // can't go through that tile - } - } - - // slither forward - var activeSnakeOldState = serializeObjectState(activeSnake); - var size1 = activeSnake.locations.length === 1; - var slitherAnimations = [ - 70, - [ - // size-1 snakes really do more of a move than a slither - size1 ? MOVE_SNAKE : SLITHER_HEAD, - activeSnake.id, - dr, - dc, - ] - ]; - activeSnake.locations.unshift(newLocation); - if (!ate) { - for(var i = 1; i 0) { - var anySnakesDied = false; - dyingObjects.forEach(function(object) { - if (object.type === SNAKE) { - // look what you've done - var oldState = serializeObjectState(object); - object.dead = true; - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - anySnakesDied = true; - } else if (object.type === BLOCK) { - // a box fell off the world - removeAnimatedObject(object, changeLog); - removeFromArray(fallingObjects, object); - exitAnimationQueue.push([ - 200, - [ - DIE_BLOCK, - object.id, - 0, 0 - ], - ]); - didAnything = true; - } else throw unreachable(); - }); - if (anySnakesDied) break; - } - if (fallingObjects.length > 0) { - moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); - didAnything = true; + // did you just push your face into a portal? + var portalLocations = getActivePortalLocations(); + var portalActivationLocations = []; + if (portalLocations.indexOf(newLocation) !== -1) { + portalActivationLocations.push(newLocation); } - - occupiedClosedLift = openLift(occupiedClosedLift, changeLog); + // push everything, too + moveObjects(pushedObjects, dr, dc, portalLocations, portalActivationLocations, changeLog, slitherAnimations); + animationQueue.push(slitherAnimations); - if (!didAnything) break; - Array.prototype.push.apply(animationQueue, exitAnimationQueue); - if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); - } + occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); + + // gravity loop + var stateToAnimationIndex = {}; + if (isGravity()) for (var fallHeight = 1; ; fallHeight++) { + var serializedState = serializeObjects(level.objects); + var infiniteLoopStartIndex = stateToAnimationIndex[serializedState]; + if (infiniteLoopStartIndex != null) { + // infinite loop + animationQueue.push([0, [INFINITE_LOOP, animationQueue.length - infiniteLoopStartIndex]]); + break; + } else { + stateToAnimationIndex[serializedState] = animationQueue.length; + } + // do portals separate from falling logic + if (portalActivationLocations.length === 1) { + var portalAnimations = [500]; + if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { + animationQueue.push(portalAnimations); + } + portalActivationLocations = []; + } + // now do falling logic + var didAnything = false; + var fallingAnimations = [ + 70 / Math.sqrt(fallHeight), + ]; + var exitAnimationQueue = []; + + // check for exit + if (!isUneatenFruit()) { //Gooby + var snakes = getSnakes(); + for (var i = 0; i < snakes.length; i++) { + var snake = snakes[i]; + if (level.map[snake.locations[0]] === EXIT) { + // (one of) you made it! + removeAnimatedObject(snake, changeLog); + exitAnimationQueue.push([ + 200, + [EXIT_SNAKE, snake.id, 0, 0], + ]); + didAnything = true; + } + } + } + + occupiedClosedLift = combineOldAndNewLiftOccupations(occupiedClosedLift); - pushUndo(unmoveStuff, changeLog); - render(); + // fall + var dyingObjects = []; + var fallingObjects = level.objects.filter(function (object) { + if (object.type === FRUIT) return; // can't fall + var theseDyingObjects = []; + if (!checkMovement(null, object, 1, 0, [], theseDyingObjects)) return false; + // this object can fall. maybe more will fall with it too. we'll check those separately. + theseDyingObjects.forEach(function (object) { + addIfNotPresent(dyingObjects, object); + }); + return true; + }); + if (dyingObjects.length > 0) { + var anySnakesDied = false; + dyingObjects.forEach(function (object) { + if (object.type === SNAKE) { + // look what you've done + var oldState = serializeObjectState(object); + object.dead = true; + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + anySnakesDied = true; + } else if (object.type === BLOCK) { + // a box fell off the world + removeAnimatedObject(object, changeLog); + removeFromArray(fallingObjects, object); + exitAnimationQueue.push([ + 200, + [ + DIE_BLOCK, + object.id, + 0, 0 + ], + ]); + didAnything = true; + } else throw unreachable(); + }); + if (anySnakesDied) break; + } + if (fallingObjects.length > 0) { + moveObjects(fallingObjects, 1, 0, portalLocations, portalActivationLocations, changeLog, fallingAnimations); + didAnything = true; + } + + occupiedClosedLift = openLift(occupiedClosedLift, changeLog); + + if (!didAnything) break; + Array.prototype.push.apply(animationQueue, exitAnimationQueue); + if (fallingAnimations.length > 1) animationQueue.push(fallingAnimations); + } + + pushUndo(unmoveStuff, changeLog); + render(); } -function combineOldAndNewLiftOccupations(oldOccupiedClosedLift) -{ - var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); - var newlyOccupiedClosedLift = getSetSubtract(newOccupiedClosedLift, oldOccupiedClosedLift); - return oldOccupiedClosedLift.concat(newlyOccupiedClosedLift); +function combineOldAndNewLiftOccupations(oldOccupiedClosedLift) { + var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); + var newlyOccupiedClosedLift = getSetSubtract(newOccupiedClosedLift, oldOccupiedClosedLift); + return oldOccupiedClosedLift.concat(newlyOccupiedClosedLift); } -function openLift(oldOccupiedClosedLift, changeLog) -{ - var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); - var nowUnoccupiedClosedLift = getSetSubtract(oldOccupiedClosedLift, newOccupiedClosedLift); - for (var i = 0; i < nowUnoccupiedClosedLift.length; i++) { - paintTileAtLocation(nowUnoccupiedClosedLift[i], OPENLIFT, changeLog); - } - return newOccupiedClosedLift; +function openLift(oldOccupiedClosedLift, changeLog) { + var newOccupiedClosedLift = getOccupiedClosedLiftLocations(); + var nowUnoccupiedClosedLift = getSetSubtract(oldOccupiedClosedLift, newOccupiedClosedLift); + for (var i = 0; i < nowUnoccupiedClosedLift.length; i++) { + paintTileAtLocation(nowUnoccupiedClosedLift[i], OPENLIFT, changeLog); + } + return newOccupiedClosedLift; } function getSetSubtract(array1, array2) { - if (array1.length === 0) return []; - return array1.filter(function(x) { return array2.indexOf(x) == -1; }); + if (array1.length === 0) return []; + return array1.filter(function (x) { return array2.indexOf(x) == -1; }); } function checkMovement(pusher, pushedObject, dr, dc, pushedObjects, dyingObjects) { - // pusher can be null (for gravity) - pushedObjects.push(pushedObject); - // find forward locations - var forwardLocations = []; - for (var i = 0; i < pushedObjects.length; i++) { - pushedObject = pushedObjects[i]; - for (var j = 0; j < pushedObject.locations.length; j++) { - var rowcol = getRowcol(level, pushedObject.locations[j]); - var forwardRowcol = {r:rowcol.r + dr, c:rowcol.c + dc}; - if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { - if (dyingObjects == null) { - // can't push things out of bounds - return false; - } else { - // this thing is going to fall out of bounds - addIfNotPresent(dyingObjects, pushedObject); - addIfNotPresent(pushedObjects, pushedObject); - continue; - } - } - var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); - if (dr === 1 && level.map[forwardLocation] === PLATFORM) { - // this platform holds us, unless we're going through it - var neighborLocations; - if (pushedObject.type === SNAKE) { - neighborLocations = []; - if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); - if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); - } else if (pushedObject.type === BLOCK) { - neighborLocations = pushedObject.locations; - } else throw asdf; - if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface - // we slip right past it - } - var yetAnotherObject = findObjectAtLocation(forwardLocation); - if (yetAnotherObject != null) { - if (yetAnotherObject.type === FRUIT) { - // not pushable - return false; - } - if (yetAnotherObject === pusher) { - // indirect pushing ourselves. - // special check for when we're indirectly pushing the tip of our own tail. - if (forwardLocation === pusher.locations[pusher.locations.length -1]) { - // for some reason this is ok. ------------ THIS IS THE TAIL GLITCH - continue; - } - return false; + // pusher can be null (for gravity) + pushedObjects.push(pushedObject); + // find forward locations + var forwardLocations = []; + for (var i = 0; i < pushedObjects.length; i++) { + pushedObject = pushedObjects[i]; + for (var j = 0; j < pushedObject.locations.length; j++) { + var rowcol = getRowcol(level, pushedObject.locations[j]); + var forwardRowcol = { r: rowcol.r + dr, c: rowcol.c + dc }; + if (!isInBounds(level, forwardRowcol.r, forwardRowcol.c)) { + if (dyingObjects == null) { + // can't push things out of bounds + return false; + } else { + // this thing is going to fall out of bounds + addIfNotPresent(dyingObjects, pushedObject); + addIfNotPresent(pushedObjects, pushedObject); + continue; + } + } + var forwardLocation = getLocation(level, forwardRowcol.r, forwardRowcol.c); + if (dr === 1 && level.map[forwardLocation] === PLATFORM) { + // this platform holds us, unless we're going through it + var neighborLocations; + if (pushedObject.type === SNAKE) { + neighborLocations = []; + if (j > 0) neighborLocations.push(pushedObject.locations[j - 1]); + if (j < pushedObject.locations.length - 1) neighborLocations.push(pushedObject.locations[j + 1]); + } else if (pushedObject.type === BLOCK) { + neighborLocations = pushedObject.locations; + } else throw asdf; + if (neighborLocations.indexOf(forwardLocation) === -1) return false; // flat surface + // we slip right past it + } + var yetAnotherObject = findObjectAtLocation(forwardLocation); + if (yetAnotherObject != null) { + if (yetAnotherObject.type === FRUIT) { + // not pushable + return false; + } + if (yetAnotherObject === pusher) { + // indirect pushing ourselves. + // special check for when we're indirectly pushing the tip of our own tail. + if (forwardLocation === pusher.locations[pusher.locations.length - 1]) { + // for some reason this is ok. ------------ THIS IS THE TAIL GLITCH + continue; + } + return false; + } + addIfNotPresent(pushedObjects, yetAnotherObject); + if (level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work + } else + addIfNotPresent(forwardLocations, forwardLocation); } - addIfNotPresent(pushedObjects, yetAnotherObject); - if(level.map[forwardLocation] === WOODPLATFORM) addIfNotPresent(forwardLocations, forwardLocation); //this made wooden platform work - } else - addIfNotPresent(forwardLocations, forwardLocation); } - } - // check forward locations - for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform, saw no effect but left new code - var forwardLocation = forwardLocations[i]; - // many of these locations can be inside objects, - // but that means the tile must be air, - // and we already know pushing that object. - var tileCode = level.map[forwardLocation]; - var object = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); - if (!isTileCodeAir(pusher, object, tileCode, dr, dc)) { - if (dyingObjects != null) { - if (tileCode === SPIKE) { - // uh... which object was this again? - if (object.type === SNAKE) { - // ouch! - addIfNotPresent(dyingObjects, object); - continue; - } - - } - else if (tileCode === LAVA) { - if (object.type === SNAKE || object.type === BLOCK) { - addIfNotPresent(dyingObjects, object); - continue; - } - } - else if (tileCode === WATER) { - if (object.type === BLOCK) { - addIfNotPresent(dyingObjects, object); - continue; + // check forward locations + for (var i = 0; i < forwardLocations.length; i++) { //changed this section trying to fix wooden platform, saw no effect but left new code + var forwardLocation = forwardLocations[i]; + // many of these locations can be inside objects, + // but that means the tile must be air, + // and we already know pushing that object. + var tileCode = level.map[forwardLocation]; + var object = findObjectAtLocation(offsetLocation(forwardLocation, -dr, -dc)); + if (!isTileCodeAir(pusher, object, tileCode, dr, dc)) { + if (dyingObjects != null) { + if (tileCode === SPIKE) { + // uh... which object was this again? + if (object.type === SNAKE) { + // ouch! + addIfNotPresent(dyingObjects, object); + continue; + } + + } + else if (tileCode === LAVA) { + if (object.type === SNAKE || object.type === BLOCK) { + addIfNotPresent(dyingObjects, object); + continue; + } + } + else if (tileCode === WATER) { + if (object.type === BLOCK) { + addIfNotPresent(dyingObjects, object); + continue; + } + } } + // can't push into something solid + return false; } - } - // can't push into something solid - return false; } - } - // the push is go - return true; + // the push is go + return true; } function activateAnySnakePlease() { - var snakes = getSnakes(); - if (snakes.length === 0) return; // nope.avi - activeSnakeId = snakes[0].id; + var snakes = getSnakes(); + if (snakes.length === 0) return; // nope.avi + activeSnakeId = snakes[0].id; } function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations, changeLog, animations) { - objects.forEach(function(object) { - var oldState = serializeObjectState(object); - var oldPortals = getSetIntersection(portalLocations, object.locations); - for (var i = 0; i < object.locations.length; i++) { - object.locations[i] = offsetLocation(object.locations[i], dr, dc); - if (level.map[object.locations[i]] == BUBBLE || level.map[object.locations[i]] == CLOUD) - paintTileAtLocation(object.locations[i], SPACE, changeLog); - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); - animations.push([ - "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK - object.id, - dr, - dc, - ]); - - var newPortals = getSetIntersection(portalLocations, object.locations); - var activatingPortals = newPortals.filter(function(portalLocation) { - return oldPortals.indexOf(portalLocation) === -1; + objects.forEach(function (object) { + var oldState = serializeObjectState(object); + var oldPortals = getSetIntersection(portalLocations, object.locations); + for (var i = 0; i < object.locations.length; i++) { + object.locations[i] = offsetLocation(object.locations[i], dr, dc); + if (level.map[object.locations[i]] == BUBBLE || level.map[object.locations[i]] == CLOUD) + paintTileAtLocation(object.locations[i], SPACE, changeLog); + } + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + animations.push([ + "m" + object.type, // MOVE_SNAKE | MOVE_BLOCK + object.id, + dr, + dc, + ]); + + var newPortals = getSetIntersection(portalLocations, object.locations); + var activatingPortals = newPortals.filter(function (portalLocation) { + return oldPortals.indexOf(portalLocation) === -1; + }); + if (activatingPortals.length === 1) { + // exactly one new portal we're touching. activate it + portalActivationLocations.push(activatingPortals[0]); + } }); - if (activatingPortals.length === 1) { - // exactly one new portal we're touching. activate it - portalActivationLocations.push(activatingPortals[0]); - } - }); } function activatePortal(portalLocations, portalLocation, animations, changeLog) { - var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; - var portalRowcol = getRowcol(level, portalLocation); - var otherPortalRowcol = getRowcol(level, otherPortalLocation); - var delta = {r:otherPortalRowcol.r - portalRowcol.r, c:otherPortalRowcol.c - portalRowcol.c}; - - var object = findObjectAtLocation(portalLocation); - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r + delta.r; - var c = rowcol.c + delta.c; - if (!isInBounds(level, r, c)) return false; // out of bounds - newLocations.push(getLocation(level, r, c)); - } - - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile - var otherObject = findObjectAtLocation(location); - if (otherObject != null && otherObject !== object) return; // blocked by object - } - - // zappo presto! - var oldState = serializeObjectState(object); - object.locations = newLocations; - for (var i = 0; i < newLocations.length; i++) { - var location = newLocations[i]; - if (level.map[location] == BUBBLE || level.map[location] == CLOUD) //changed this despite bubble working perfectly without it - paintTileAtLocation(location, SPACE, changeLog); - } - changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); + var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; + var portalRowcol = getRowcol(level, portalLocation); + var otherPortalRowcol = getRowcol(level, otherPortalLocation); + var delta = { r: otherPortalRowcol.r - portalRowcol.r, c: otherPortalRowcol.c - portalRowcol.c }; + + var object = findObjectAtLocation(portalLocation); + var newLocations = []; + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r + delta.r; + var c = rowcol.c + delta.c; + if (!isInBounds(level, r, c)) return false; // out of bounds + newLocations.push(getLocation(level, r, c)); + } + + for (var i = 0; i < newLocations.length; i++) { + var location = newLocations[i]; + if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile + var otherObject = findObjectAtLocation(location); + if (otherObject != null && otherObject !== object) return; // blocked by object + } + + // zappo presto! + var oldState = serializeObjectState(object); + object.locations = newLocations; + for (var i = 0; i < newLocations.length; i++) { + var location = newLocations[i]; + if (level.map[location] == BUBBLE || level.map[location] == CLOUD) //changed this despite bubble working perfectly without it + paintTileAtLocation(location, SPACE, changeLog); + } + changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); } function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { - switch (tileCode) - { - case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; - case WOODPLATFORM: case BUBBLE: return pusher != null; - case PLATFORM: return dr != 1; - case ONEWAYWALLU: return dr != 1; - case ONEWAYWALLD: return dr != -1; - case ONEWAYWALLL: return dc != 1; - case ONEWAYWALLR: return dc != -1; - default: return false; - } + switch (tileCode) { + case SPACE: case EXIT: case PORTAL: case CLOSEDLIFT: return true; + case WOODPLATFORM: case BUBBLE: return pusher != null; + case PLATFORM: return dr != 1; + case ONEWAYWALLU: return dr != 1; + case ONEWAYWALLD: return dr != -1; + case ONEWAYWALLL: return dc != 1; + case ONEWAYWALLR: return dc != -1; + default: return false; + } } function addIfNotPresent(array, element) { - if (array.indexOf(element) !== -1) return; - array.push(element); + if (array.indexOf(element) !== -1) return; + array.push(element); } function removeAnyObjectAtLocation(location, changeLog) { - var object = findObjectAtLocation(location); - if (object != null) removeObject(object, changeLog); + var object = findObjectAtLocation(location); + if (object != null) removeObject(object, changeLog); } function removeAnimatedObject(object, changeLog) { - removeObject(object, changeLog); - freshlyRemovedAnimatedObjects.push(object); + removeObject(object, changeLog); + freshlyRemovedAnimatedObjects.push(object); } function removeObject(object, changeLog) { - removeFromArray(level.objects, object); - changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0,[]]]); - if (object.type === SNAKE && object.id === activeSnakeId) { - activateAnySnakePlease(); - } - if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { - // no longer editing an object that doesn't exit - paintBrushBlockId = null; - } - if (object.type === BLOCK) { - delete blockSupportRenderCache[object.id]; - } + removeFromArray(level.objects, object); + changeLog.push([object.type, object.id, [object.dead, copyArray(object.locations)], [0, []]]); + if (object.type === SNAKE && object.id === activeSnakeId) { + activateAnySnakePlease(); + } + if (object.type === BLOCK && paintBrushTileCode === BLOCK && paintBrushBlockId === object.id) { + // no longer editing an object that doesn't exit + paintBrushBlockId = null; + } + if (object.type === BLOCK) { + delete blockSupportRenderCache[object.id]; + } } function removeFromArray(array, element) { - var index = array.indexOf(element); - if (index === -1) throw unreachable(); - array.splice(index, 1); + var index = array.indexOf(element); + if (index === -1) throw unreachable(); + array.splice(index, 1); } function findActiveSnake() { - var snakes = getSnakes(); - for (var i = 0; i < snakes.length; i++) { - if (snakes[i].id === activeSnakeId) return snakes[i]; - } - throw unreachable(); + var snakes = getSnakes(); + for (var i = 0; i < snakes.length; i++) { + if (snakes[i].id === activeSnakeId) return snakes[i]; + } + throw unreachable(); } function findBlockById(id) { - return findObjectOfTypeAndId(BLOCK, id); + return findObjectOfTypeAndId(BLOCK, id); } function findSnakesOfColor(color) { - return level.objects.filter(function(object) { - if (object.type !== SNAKE) return false; - return object.id % snakeColors.length === color; - }); + return level.objects.filter(function (object) { + if (object.type !== SNAKE) return false; + return object.id % snakeColors.length === color; + }); } function findObjectOfTypeAndId(type, id) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.type === type && object.id === id) return object; - } - return null; + for (var i = 0; i < level.objects.length; i++) { + var object = level.objects[i]; + if (object.type === type && object.id === id) return object; + } + return null; } function findObjectAtLocation(location) { - for (var i = 0; i < level.objects.length; i++) { - var object = level.objects[i]; - if (object.locations.indexOf(location) !== -1) - return object; - } - return null; + for (var i = 0; i < level.objects.length; i++) { + var object = level.objects[i]; + if (object.locations.indexOf(location) !== -1) + return object; + } + return null; } function isUneatenFruit() { - return getObjectsOfType(FRUIT).length > 0; + return getObjectsOfType(FRUIT).length > 0; } function getActivePortalLocations() { - var portalLocations = getPortalLocations(); - if (portalLocations.length !== 2) return []; // nice try - return portalLocations; + var portalLocations = getPortalLocations(); + if (portalLocations.length !== 2) return []; // nice try + return portalLocations; } function getPortalLocations() { - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === PORTAL) result.push(i); - } - return result; + var result = []; + for (var i = 0; i < level.map.length; i++) { + if (level.map[i] === PORTAL) result.push(i); + } + return result; } function countSnakes() { - return getSnakes().length; + return getSnakes().length; } function getSnakes() { - return getObjectsOfType(SNAKE); + return getObjectsOfType(SNAKE); } function getBlocks() { - return getObjectsOfType(BLOCK); -} -function getOccupiedClosedLiftLocations() -{ - var result = []; - for (var i = 0; i < level.map.length; i++) { - if (level.map[i] === CLOSEDLIFT) { - if (findObjectAtLocation(i)) - result.push(i); + return getObjectsOfType(BLOCK); +} +function getOccupiedClosedLiftLocations() { + var result = []; + for (var i = 0; i < level.map.length; i++) { + if (level.map[i] === CLOSEDLIFT) { + if (findObjectAtLocation(i)) + result.push(i); + } } - } - return result; + return result; } function getObjectsOfType(type) { - return level.objects.filter(function(object) { - return object.type == type; - }); + return level.objects.filter(function (object) { + return object.type == type; + }); } function isDead() { - if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; - return getSnakes().filter(function(snake) { - return !!snake.dead; - }).length > 0; + if (animationQueue.length > 0 && animationQueue[animationQueue.length - 1][1][0] === INFINITE_LOOP) return true; + return getSnakes().filter(function (snake) { + return !!snake.dead; + }).length > 0; } function isAlive() { - return countSnakes() > 0 && !isDead(); + return countSnakes() > 0 && !isDead(); } var activeSnakeId = null; @@ -2027,22 +2023,22 @@ var DIE_SNAKE = "ds"; var DIE_BLOCK = "db"; var INFINITE_LOOP = "il"; var animationQueue = [ - // // sequence of disjoint animation groups. - // // each group completes before the next begins. - // [ - // 70, // duration of this animation group - // // multiple things to animate simultaneously - // [ - // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, - // objectId, - // dr, - // dc, - // ], - // [ - // INFINITE_LOOP, - // loopSizeNotIncludingThis, - // ], - // ], + // // sequence of disjoint animation groups. + // // each group completes before the next begins. + // [ + // 70, // duration of this animation group + // // multiple things to animate simultaneously + // [ + // SLITHER_HEAD | SLITHER_TAIL | MOVE_SNAKE | MOVE_BLOCK | TELEPORT_SNAKE | TELEPORT_BLOCK, + // objectId, + // dr, + // dc, + // ], + // [ + // INFINITE_LOOP, + // loopSizeNotIncludingThis, + // ], + // ], ]; var animationQueueCursor = 0; var animationStart = null; // new Date().getTime() @@ -2052,33 +2048,33 @@ var freshlyRemovedAnimatedObjects = []; // render the support beams for blocks into a temporary buffer, and remember it. // this is due to stencil buffers causing slowdown on some platforms. see #25. var blockSupportRenderCache = { - // id: canvas, - // "0": document.createElement("canvas"), + // id: canvas, + // "0": document.createElement("canvas"), }; function render() { - if (level == null) return; - if (animationQueueCursor < animationQueue.length) { - var animationDuration = animationQueue[animationQueueCursor][0]; - animationProgress = (new Date().getTime() - animationStart) / animationDuration; - if (animationProgress >= 1.0) { - // animation group complete - animationProgress -= 1.0; - animationQueueCursor++; - if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { - var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; - animationQueueCursor -= infiniteLoopSize; - } - animationStart = new Date().getTime(); + if (level == null) return; + if (animationQueueCursor < animationQueue.length) { + var animationDuration = animationQueue[animationQueueCursor][0]; + animationProgress = (new Date().getTime() - animationStart) / animationDuration; + if (animationProgress >= 1.0) { + // animation group complete + animationProgress -= 1.0; + animationQueueCursor++; + if (animationQueueCursor < animationQueue.length && animationQueue[animationQueueCursor][1][0] === INFINITE_LOOP) { + var infiniteLoopSize = animationQueue[animationQueueCursor][1][1]; + animationQueueCursor -= infiniteLoopSize; + } + animationStart = new Date().getTime(); + } } - } - if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; - canvas.width = tileSize * level.width; - canvas.height = tileSize * level.height; - var context = canvas.getContext("2d"); //Gooby - - themeName = themes[themeCounter][0]; - if(themeName!="sky"){ + if (animationQueueCursor === animationQueue.length) animationProgress = 1.0; + canvas.width = tileSize * level.width; + canvas.height = tileSize * level.height; + var context = canvas.getContext("2d"); //Gooby + + themeName = themes[themeCounter][0]; + if (themeName != "sky") { background = themes[themeCounter][1]; material = themes[themeCounter][2]; surface = themes[themeCounter][3]; @@ -2089,768 +2085,751 @@ function render() { fruitColors = themes[themeCounter][8]; textStyle = themes[themeCounter][10]; experimentalColors = themes[themeCounter][11]; - - if(background.substr(0,1) == "#") { + + if (background.substr(0, 1) == "#") { context.fillStyle = background; context.fillRect(0, 0, canvas.width, canvas.height); } - else{ - for(var i = 0; i maxR) maxR = rowcol.r; - if (rowcol.c < minC) minC = rowcol.c; - if (rowcol.c > maxC) maxC = rowcol.c; - }); - var image = blockSupportRenderCache[object.id]; - if (image == null) { - // render the support beams to a buffer - blockSupportRenderCache[object.id] = image = document.createElement("canvas"); - image.width = (maxC - minC + 1) * tileSize; - image.height = (maxR - minR + 1) * tileSize; - var bufferContext = image.getContext("2d"); - // Make a stencil that excludes the insides of blocks. - // Then when we render the support beams, we won't see the supports inside the block itself. - bufferContext.beginPath(); - // Draw a path around the whole screen in the opposite direction as the rectangle paths below. - // This means that the below rectangles will be removing area from the greater rectangle. - bufferContext.rect(image.width, 0, -image.width, image.height); - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(level, object.locations[i]); - var r = rowcol.r - minR; - var c = rowcol.c - minC; - bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); - } - bufferContext.clip(); - for (var i = 0; i < object.locations.length - 1; i++) { - var rowcol1 = getRowcol(level, object.locations[i]); - rowcol1.r -= minR; - rowcol1.c -= minC; - var rowcol2 = getRowcol(level, object.locations[i + 1]); - rowcol2.r -= minR; - rowcol2.c -= minC; - var cornerRowcol = {r:rowcol1.r, c:rowcol2.c}; - drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - } - } - var r = minR + animationDisplacementRowcol.r; - var c = minC + animationDisplacementRowcol.c; - context.drawImage(image, c * tileSize, r * tileSize); - }); - - if(!cs) { - // terrain - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - var location = getLocation(level, r, c); - var tileCode = level.map[location]; - drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids - } - } - } - for(var i = 0; i maxR) maxR = rowcol.r; + if (rowcol.c < minC) minC = rowcol.c; + if (rowcol.c > maxC) maxC = rowcol.c; + }); + var image = blockSupportRenderCache[object.id]; + if (image == null) { + // render the support beams to a buffer + blockSupportRenderCache[object.id] = image = document.createElement("canvas"); + image.width = (maxC - minC + 1) * tileSize; + image.height = (maxR - minR + 1) * tileSize; + var bufferContext = image.getContext("2d"); + // Make a stencil that excludes the insides of blocks. + // Then when we render the support beams, we won't see the supports inside the block itself. + bufferContext.beginPath(); + // Draw a path around the whole screen in the opposite direction as the rectangle paths below. + // This means that the below rectangles will be removing area from the greater rectangle. + bufferContext.rect(image.width, 0, -image.width, image.height); + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(level, object.locations[i]); + var r = rowcol.r - minR; + var c = rowcol.c - minC; + bufferContext.rect(c * tileSize, r * tileSize, tileSize, tileSize); + } + bufferContext.clip(); + for (var i = 0; i < object.locations.length - 1; i++) { + var rowcol1 = getRowcol(level, object.locations[i]); + rowcol1.r -= minR; + rowcol1.c -= minC; + var rowcol2 = getRowcol(level, object.locations[i + 1]); + rowcol2.r -= minR; + rowcol2.c -= minC; + var cornerRowcol = { r: rowcol1.r, c: rowcol2.c }; + drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); + drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); + } + } + var r = minR + animationDisplacementRowcol.r; + var c = minC + animationDisplacementRowcol.c; + context.drawImage(image, c * tileSize, r * tileSize); + }); } - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - location = getLocation(level, r, c); - tileCode = level.map[location]; - if(tileCode === WALL) drawTile(tileCode, r, c, level, location, false); //draws only walls + if (!cs) { + // terrain + if (onlyTheseObjects == null) { + for (var r = 0; r < level.height; r++) { + for (var c = 0; c < level.width; c++) { + var location = getLocation(level, r, c); + var tileCode = level.map[location]; + drawTile(tileCode, r, c, level, location, true); //draws all but walls and liquids + } + } } - } - } - if (onlyTheseObjects == null) { - for (var r = 0; r < level.height; r++) { - for (var c = 0; c < level.width; c++) { - location = getLocation(level, r, c); - tileCode = level.map[location]; - if(tileCode === CLOUD || tileCode === LAVA || tileCode === WATER) drawTile(tileCode, r, c, level, location, false); //draws only clouds + for (var i = 0; i < objects.length; i++) { + var object = objects[i]; + if (object.type === SNAKE || object.type === BLOCK) drawObject(object); //draws snakes and blocks } - } - } - for(var i = 0; i6) { color= color.substring(1,color.length)} - var rgb = parseInt(color, 16); - var r = Math.abs(((rgb >> 16) & 0xFF)+v); if (r>255) r=r-(r-255); - var g = Math.abs(((rgb >> 8) & 0xFF)+v); if (g>255) g=g-(g-255); - var b = Math.abs((rgb & 0xFF)+v); if (b>255) b=b-(b-255); - r = Number(r < 0 || isNaN(r)) ? 0 : ((r > 255) ? 255 : r).toString(16); - if (r.length == 1) r = '0' + r; - g = Number(g < 0 || isNaN(g)) ? 0 : ((g > 255) ? 255 : g).toString(16); - if (g.length == 1) g = '0' + g; - b = Number(b < 0 || isNaN(b)) ? 0 : ((b > 255) ? 255 : b).toString(16); - if (b.length == 1) b = '0' + b; - return "#" + r + g + b; -} - - function drawObject(object) { - switch (object.type) { - case SNAKE: - var falling = false; - var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); - if (animationDisplacementRowcol.r != 0) falling = true; - var lastRowcol = null - var nextRowcol = null - var color = snakeColors[object.id % snakeColors.length]; - var colorIndex = object.id % snakeColors.length; - var altColor = getTintedColor(color, 50); - if(themeName==="Classic") altColor = color; - var headRowcol; - var orientation = 10; - for (var i = 0; i < object.locations.length; i++) { - var animation; - var rowcol; - if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward - rowcol = getRowcol(level, object.locations[i]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else if (i === object.locations.length) { - // animated tail? - if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { - // animate tail slithering to catch up - rowcol = getRowcol(level, object.locations[i-1]); - rowcol.r += animation[2] * (animationProgress - 1); - rowcol.c += animation[3] * (animationProgress - 1); - } else { - // no animated tail needed - break; - } - } else rowcol = getRowcol(level, object.locations[i]); - - lastRowcol = getRowcol(level, object.locations[i-1]); //closer to head - nextRowcol = getRowcol(level, object.locations[i+1]); //closer to tail - var rc = rowcol; - var lrc = lastRowcol; - var nrc = nextRowcol; - - if (object.dead) { //if snake dies after moving left or right, head is positioned down - rowcol.r += .5; - lastRowcol.r += .5; - nextRowcol.r += .5; - falling = true; - } - rowcol.r += animationDisplacementRowcol.r; - rowcol.c += animationDisplacementRowcol.c; - lastRowcol.r += animationDisplacementRowcol.r; - lastRowcol.c += animationDisplacementRowcol.c; - nextRowcol.r += animationDisplacementRowcol.r; - nextRowcol.c += animationDisplacementRowcol.c; - - var cx = rowcol.c * tileSize; - var cy = rowcol.r * tileSize; - - if (i === 0) { - context.fillStyle = color; - headRowcol = rowcol; - - //determines orientation of face - if(!falling) nextRowcol = getRowcol(level, object.locations[1]); - if (nextRowcol.r < rowcol.r) { //last move down - roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false); //draw head - if(colorIndex === 0) orientation = 2; - else if(colorIndex === 1) orientation = 6; - else if(colorIndex === 2) orientation = 3; - else if(colorIndex === 3) orientation = 5; - } - else if (nextRowcol.r > rowcol.r) { //last move up - roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false); //draw head - if(colorIndex === 0) orientation = 0; - else if(colorIndex === 1) orientation = 4; - else if(colorIndex === 2) orientation = 1; - else if(colorIndex === 3) orientation = 7; - } - else if (nextRowcol.c < rowcol.c) { //last move right - roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false); //draw head - if(colorIndex === 0) orientation = 1; - else if(colorIndex === 1) orientation = 5; - else if(colorIndex === 2) orientation = 2; - else if(colorIndex === 3) orientation = 4; - } - else if (nextRowcol.c > rowcol.c) { //last move left - roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false); //draw head - if(colorIndex === 0) orientation = 3; - else if(colorIndex === 1) orientation = 7; - else if(colorIndex === 2) orientation = 0; - else if(colorIndex === 3) orientation = 6; - } - else { - roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); //draw head - orientation = 10; - } - } else { - if(i % 2 == 0) context.fillStyle = color; - else context.fillStyle = altColor; - - if (i === object.locations.length-1) { - if(lastRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,tr:10}, true, false);} - else if(lastRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10,br:10}, true, false);} - else if(lastRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10,br:10}, true, false);} - else if(lastRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10,bl:10}, true, false);} + + function getTintedColor(color, v) { + if (color.length > 6) { color = color.substring(1, color.length) } + var rgb = parseInt(color, 16); + var r = Math.abs(((rgb >> 16) & 0xFF) + v); if (r > 255) r = r - (r - 255); + var g = Math.abs(((rgb >> 8) & 0xFF) + v); if (g > 255) g = g - (g - 255); + var b = Math.abs((rgb & 0xFF) + v); if (b > 255) b = b - (b - 255); + r = Number(r < 0 || isNaN(r)) ? 0 : ((r > 255) ? 255 : r).toString(16); + if (r.length == 1) r = '0' + r; + g = Number(g < 0 || isNaN(g)) ? 0 : ((g > 255) ? 255 : g).toString(16); + if (g.length == 1) g = '0' + g; + b = Number(b < 0 || isNaN(b)) ? 0 : ((b > 255) ? 255 : b).toString(16); + if (b.length == 1) b = '0' + b; + return "#" + r + g + b; + } + + function drawObject(object) { + switch (object.type) { + case SNAKE: + var falling = false; + var animationDisplacementRowcol = findAnimationDisplacementRowcol(object.type, object.id); + if (animationDisplacementRowcol.r != 0) falling = true; + var lastRowcol = null + var nextRowcol = null + var color = snakeColors[object.id % snakeColors.length]; + var colorIndex = object.id % snakeColors.length; + var altColor = getTintedColor(color, 50); + if (themeName === "Classic") altColor = color; + var headRowcol; + var orientation = 10; + for (var i = 0; i < object.locations.length; i++) { + var animation; + var rowcol; + if (i === 0 && (animation = findAnimation([SLITHER_HEAD], object.id)) != null) { // animate head slithering forward + rowcol = getRowcol(level, object.locations[i]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else if (i === object.locations.length) { + // animated tail? + if ((animation = findAnimation([SLITHER_TAIL], object.id)) != null) { + // animate tail slithering to catch up + rowcol = getRowcol(level, object.locations[i - 1]); + rowcol.r += animation[2] * (animationProgress - 1); + rowcol.c += animation[3] * (animationProgress - 1); + } else { + // no animated tail needed + break; + } + } else rowcol = getRowcol(level, object.locations[i]); + + lastRowcol = getRowcol(level, object.locations[i - 1]); //closer to head + nextRowcol = getRowcol(level, object.locations[i + 1]); //closer to tail + var rc = rowcol; + var lrc = lastRowcol; + var nrc = nextRowcol; + + if (object.dead) { //if snake dies after moving left or right, head is positioned down + rowcol.r += .5; + lastRowcol.r += .5; + nextRowcol.r += .5; + falling = true; + } + rowcol.r += animationDisplacementRowcol.r; + rowcol.c += animationDisplacementRowcol.c; + lastRowcol.r += animationDisplacementRowcol.r; + lastRowcol.c += animationDisplacementRowcol.c; + nextRowcol.r += animationDisplacementRowcol.r; + nextRowcol.c += animationDisplacementRowcol.c; + + var cx = rowcol.c * tileSize; + var cy = rowcol.r * tileSize; + + if (i === 0) { + context.fillStyle = color; + headRowcol = rowcol; + + //determines orientation of face + if (!falling) nextRowcol = getRowcol(level, object.locations[1]); + if (nextRowcol.r < rowcol.r) { //last move down + roundRect(context, cx, cy, tileSize, tileSize, { bl: 10, br: 10 }, true, false); //draw head + if (colorIndex === 0) orientation = 2; + else if (colorIndex === 1) orientation = 6; + else if (colorIndex === 2) orientation = 3; + else if (colorIndex === 3) orientation = 5; + } + else if (nextRowcol.r > rowcol.r) { //last move up + roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); //draw head + if (colorIndex === 0) orientation = 0; + else if (colorIndex === 1) orientation = 4; + else if (colorIndex === 2) orientation = 1; + else if (colorIndex === 3) orientation = 7; + } + else if (nextRowcol.c < rowcol.c) { //last move right + roundRect(context, cx, cy, tileSize, tileSize, { tr: 10, br: 10 }, true, false); //draw head + if (colorIndex === 0) orientation = 1; + else if (colorIndex === 1) orientation = 5; + else if (colorIndex === 2) orientation = 2; + else if (colorIndex === 3) orientation = 4; + } + else if (nextRowcol.c > rowcol.c) { //last move left + roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); //draw head + if (colorIndex === 0) orientation = 3; + else if (colorIndex === 1) orientation = 7; + else if (colorIndex === 2) orientation = 0; + else if (colorIndex === 3) orientation = 6; + } + else { + roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); //draw head + orientation = 10; + } + } else { + if (i % 2 == 0) context.fillStyle = color; + else context.fillStyle = altColor; + + if (i === object.locations.length - 1) { + if (lastRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); } + else if (lastRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10, br: 10 }, true, false); } + else if (lastRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10, br: 10 }, true, false); } + else if (lastRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); } + } + else if (i != object.locations.length - 1 && i != object.locations.length) { + if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10 }, true, false); } + else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10 }, true, false); } + else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { br: 10 }, true, false); } + else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10 }, true, false); } + + else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10 }, true, false); } + else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10 }, true, false); } + else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { br: 10 }, true, false); } + else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10 }, true, false); } + + else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, 0, true, false); } + } + else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); + } } - else if (i != object.locations.length-1 && i != object.locations.length) { - if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} - else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} - else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} - else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} - - else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {bl:10}, true, false);} - else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tl:10}, true, false);} - else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {br:10}, true, false);} - else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, {tr:10}, true, false);} - - else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) {roundRect(context, cx, cy, tileSize, tileSize, 0, true, false);} + drawFace(object.id, headRowcol.c, headRowcol.r, orientation); + break; + case BLOCK: + drawBlock(object); + break; + case FRUIT: + rowcol = getRowcol(level, object.locations[0]); + var c = rowcol.c; + var r = rowcol.r; + var startC = c * tileSize + tileSize / 2; + var startR = r * tileSize + tileSize * .2; + var resize = tileSize * 1.7; + context.fillStyle = fruitColors[object.id % fruitColors.length]; + if (themeName != "Classic") { + if (surface == "rainbow") { + context.fillStyle = "black"; + context.lineWidth = tileSize / 8; + context.strokeStyle = "white"; + resize = tileSize * 1.4; + } + //context.fillStyle = "#ff6b45"; + context.beginPath(); + context.moveTo(startC, startR); + context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC - resize * .25, startR - resize * .1, startC - resize * .3, startR + resize * .05); + context.bezierCurveTo(startC - resize * .35, startR + resize * .15, startC - resize * .3, startR + resize * .6, startC, startR + resize * .5); + context.bezierCurveTo(startC + resize * .3, startR + resize * .6, startC + resize * .35, startR + resize * .15, startC + resize * .3, startR + resize * .05); + context.bezierCurveTo(startC + resize * .25, startR - resize * .05, startC + resize * .1, startR - resize * .1, startC, startR); + context.closePath(); + context.fill(); + if (surface == "rainbow") context.stroke(); + + context.beginPath(); + context.moveTo(startC, startR); + context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC, startR - resize * .1, startC - resize * .1, startR - resize * .15); + context.bezierCurveTo(startC, startR - resize * .1, startC + resize * .05, startR - resize * .1, startC, startR); + context.fillStyle = themes[themeCounter][9]; + context.fill(); } - else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); - } + else drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); + break; + default: throw unreachable(); } - drawFace(object.id, headRowcol.c, headRowcol.r, orientation); - break; - case BLOCK: - drawBlock(object); - break; - case FRUIT: - rowcol = getRowcol(level, object.locations[0]); - var c = rowcol.c; - var r = rowcol.r; - var startC = c*tileSize+tileSize/2; - var startR = r*tileSize+tileSize*.2; - var resize = tileSize * 1.7; - context.fillStyle = fruitColors[object.id % fruitColors.length]; - if(themeName != "Classic"){ - if(surface == "rainbow") { - context.fillStyle = "black"; - context.lineWidth = tileSize/8; - context.strokeStyle = "white"; - resize = tileSize * 1.4; - } - //context.fillStyle = "#ff6b45"; - context.beginPath(); - context.moveTo(startC, startR); - context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC-resize*.25, startR-resize*.1, startC-resize*.3, startR+resize*.05); - context.bezierCurveTo(startC-resize*.35, startR+resize*.15, startC-resize*.3, startR+resize*.6, startC, startR+resize*.5); - context.bezierCurveTo(startC+resize*.3, startR+resize*.6, startC+resize*.35, startR+resize*.15, startC+resize*.3, startR+resize*.05); - context.bezierCurveTo(startC+resize*.25, startR-resize*.05, startC+resize*.1, startR-resize*.1, startC, startR); - context.closePath(); - context.fill(); - if(surface == "rainbow") context.stroke(); + } - context.beginPath(); - context.moveTo(startC,startR); - context.bezierCurveTo(startC-resize*.1, startR-resize*.05, startC, startR-resize*.1, startC-resize*.1, startR-resize*.15); - context.bezierCurveTo(startC, startR-resize*.1, startC+resize*.05, startR-resize*.1, startC, startR); - context.fillStyle = themes[themeCounter][9]; - context.fill(); + function drawPlatform(r, c, adjacentTiles) { + newPlatform(r, c, isPlatform); + + function isPlatform(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === PLATFORM; } - else drawCircle(rowcol.r, rowcol.c, 1, "#f0f"); - break; - default: throw unreachable(); + + /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.1429); + context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.2857); + context.lineTo(c*tileSize+tileSize*1, r*tileSize); + context.lineTo(c*tileSize, r*tileSize); + context.closePath(); + context.rect(c*tileSize, r*tileSize+tileSize*.2857, tileSize, tileSize*.1429);*/ + + /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2); + context.bezierCurveTo(c*tileSize+tileSize*.25, r*tileSize+tileSize*.2, c*tileSize+tileSize*.25, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); + context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.75, r*tileSize+tileSize*.2, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); + context.lineTo((c+1)*tileSize, r*tileSize); + context.lineTo(c*tileSize, r*tileSize);*/ + + /*context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.arc((c + 3/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.arc((c + 1/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); + context.lineTo(c*tileSize, r*tileSize); + context.lineTo(c*tileSize+tileSize, r*tileSize);*/ + + //context.closePath(); + //context.fillStyle = "#000066"; + //ontext.fill(); + //context.stroke(); } - } - -function drawPlatform(r, c, adjacentTiles) { - newPlatform(r, c, isPlatform); - - function isPlatform(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === PLATFORM; + + function newPlatform(r, c, isOccupied) { + + var x1 = .05; + var x2 = .05; + if (isOccupied(-1, 0)) x1 = 0; + if (isOccupied(1, 0)) x2 = 0; + + var platformColors = ["#ffcccc", "#ffe0cc", "#ffffcc", "#e6ffe6", "#e6e6ff"]; + for (var i = 0; i < 5; i++) { + var j = i - 1; + if (j < 0) j = 0; + context.beginPath(); + context.moveTo(c * tileSize + tileSize * (i * x1), r * tileSize + tileSize * (.05 + (.1 * i) - (j * .02))); + context.strokeStyle = platformColors[i]; + context.lineWidth = tileSize * (.1 - (i * .02)); + context.lineTo(c * tileSize + tileSize * (1 - (i * x2)), r * tileSize + tileSize * (.05 + (.1 * i) - (j * .02))); + context.stroke(); + } } - - /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.1429, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.2857, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.4286, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.5714, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*.7143, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.1429); - context.lineTo(c*tileSize+tileSize*.8571, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*1, r*tileSize+tileSize*.2857); - context.lineTo(c*tileSize+tileSize*1, r*tileSize); - context.lineTo(c*tileSize, r*tileSize); - context.closePath(); - context.rect(c*tileSize, r*tileSize+tileSize*.2857, tileSize, tileSize*.1429);*/ - - /*context.lineTo(c*tileSize, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.25, r*tileSize+tileSize*.2, c*tileSize+tileSize*.25, r*tileSize+tileSize*.3, c*tileSize+tileSize*.5, r*tileSize+tileSize*.3); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.75, r*tileSize+tileSize*.2, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo((c+1)*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize);*/ - - /*context.arc((c + 5/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.arc((c + 3/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.arc((c + 1/6) * tileSize, (r + 1/6) * tileSize, tileSize/6, 0, Math.PI); - context.lineTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize, r*tileSize);*/ - - //context.closePath(); - //context.fillStyle = "#000066"; - //ontext.fill(); - //context.stroke(); -} - -function newPlatform(r, c, isOccupied){ - - var x1 = .05; - var x2 = .05; - if(isOccupied(-1,0)) x1 = 0; - if(isOccupied(1,0)) x2 = 0; - - var platformColors = ["#ffcccc", "#ffe0cc", "#ffffcc", "#e6ffe6", "#e6e6ff"]; - for(var i = 0; i<5; i++){ - var j = i-1; - if(j<0) j = 0; + + function drawOneWayWall(fillStyle, r, c, dr, dc) { + context.lineWidth = 2; + context.strokeStyle = "#333"; context.beginPath(); - context.moveTo(c*tileSize+tileSize*(i*x1), r*tileSize+tileSize*(.05 + (.1 * i) - (j * .02))); - context.strokeStyle = platformColors[i]; - context.lineWidth = tileSize*(.1-(i*.02)); - context.lineTo(c*tileSize+tileSize*(1-(i*x2)), r*tileSize+tileSize*(.05 + (.1 * i) - (j * .02))); + + if (dr == -1) { + context.moveTo(c * tileSize, r * tileSize + tileSize / 2); + context.lineTo(c * tileSize + tileSize / 4, r * tileSize + tileSize / 4); + context.stroke(); + context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + tileSize / 4); + context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize / 2); + } + else if (dr == 1) { + context.moveTo(c * tileSize, r * tileSize + tileSize / 2); + context.lineTo(c * tileSize + tileSize / 4, r * tileSize + 3 * tileSize / 4); + context.stroke(); + context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + 3 * tileSize / 4); + context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize / 2); + } + else if (dc == -1) { + context.moveTo(c * tileSize + tileSize / 2, r * tileSize); + context.lineTo(c * tileSize + tileSize / 4, r * tileSize + tileSize / 4); + context.stroke(); + context.moveTo(c * tileSize + tileSize / 4, r * tileSize + 3 * tileSize / 4); + context.lineTo(c * tileSize + tileSize / 2, r * tileSize + tileSize); + } + else if (dc == 1) { + context.moveTo(c * tileSize + tileSize / 2, r * tileSize); + context.lineTo(c * tileSize + 3 * tileSize / 4, r * tileSize + tileSize / 4); + context.stroke(); + context.moveTo(c * tileSize + 3 * tileSize / 4, r * tileSize + 3 * tileSize / 4); + context.lineTo(c * tileSize + tileSize / 2, r * tileSize + tileSize); + } + context.stroke(); + context.lineWidth = 0; + + context.fillStyle = fillStyle; + if (dr == -1) roundRect(context, c * tileSize - tileSize / 15, r * tileSize - tileSize / 15, tileSize + 2 * tileSize / 15, tileSize / 4 + 2 * tileSize / 15, 2, true, false); + else if (dr == 1) roundRect(context, c * tileSize - tileSize / 15, (r + 1) * tileSize - tileSize / 15 - tileSize / 4, tileSize + 2 * tileSize / 15, tileSize / 4 + 2 * tileSize / 15, 2, true, false); + else if (dc == -1) roundRect(context, c * tileSize - tileSize / 15, r * tileSize - tileSize / 15, tileSize / 4 + 2 * tileSize / 15, tileSize + 2 * tileSize / 15, 2, true, false); + else if (dc == 1) roundRect(context, (c + 1) * tileSize - tileSize / 15 - tileSize / 4, r * tileSize - tileSize / 15, tileSize / 4 + 2 * tileSize / 15, tileSize + 2 * tileSize / 15, 2, true, false); } -} - - function drawOneWayWall(fillStyle, r, c, dr, dc) { - context.lineWidth = 2; - context.strokeStyle = "#333"; - context.beginPath(); - - if (dr == -1) { - context.moveTo(c * tileSize, r * tileSize + tileSize/2); - context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); - context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); - } - else if (dr == 1) { - context.moveTo(c * tileSize, r * tileSize + tileSize/2); - context.lineTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); - context.lineTo(c * tileSize + tileSize, r * tileSize + tileSize/2); - } - else if (dc == -1) { - context.moveTo(c * tileSize + tileSize/2, r * tileSize); - context.lineTo(c * tileSize + tileSize/4, r * tileSize + tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + tileSize/4, r * tileSize + 3*tileSize/4); - context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); - } - else if (dc == 1) { - context.moveTo(c * tileSize + tileSize/2, r * tileSize); - context.lineTo(c * tileSize + 3*tileSize/4, r * tileSize + tileSize/4); - context.stroke(); - context.moveTo(c * tileSize + 3*tileSize/4, r * tileSize + 3*tileSize/4); - context.lineTo(c * tileSize + tileSize/2, r * tileSize + tileSize); - } - - context.stroke(); - context.lineWidth = 0; - - context.fillStyle = fillStyle; - if (dr == -1) roundRect(context, c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15, 2, true, false); - else if (dr == 1) roundRect(context, c * tileSize - tileSize/15, (r + 1) * tileSize - tileSize/15 - tileSize/4, tileSize + 2*tileSize/15, tileSize/4 + 2*tileSize/15, 2, true, false); - else if (dc == -1) roundRect(context, c * tileSize - tileSize/15, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15, 2, true, false); - else if (dc == 1) roundRect(context, (c + 1) * tileSize - tileSize/15 - tileSize/4, r * tileSize - tileSize/15, tileSize/4 + 2*tileSize/15, tileSize + 2*tileSize/15, 2, true, false); - } - - function drawBubble(r, c) { - bubbleX = c*tileSize; - var grd = context.createRadialGradient(bubbleX, r*tileSize, 0, bubbleX, r*tileSize, tileSize); - grd.addColorStop(0, "rgba(255,255,255,.9)"); - grd.addColorStop(1, "rgba(255,255,255,.2)"); - context.fillStyle = grd; - context.lineWidth = .5; - context.strokeStyle = "rgba(200,200,200,.2)"; - - context.beginPath(); - context.arc(c*tileSize+tileSize*.5, r*tileSize+tileSize*.5, tileSize/2, 0, 2*Math.PI); - context.fill(); - context.stroke(); - } - -function drawLiquid(r, c, type, adjacentTiles) { - newLiquid(r, c, type, isSameLiquid); - - function isSameLiquid(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === type; - } -} - -function newLiquid(r, c, type, isOccupied){ - context.save(); - var tubColor; - if(type == LAVA) { - context.fillStyle = "#ffbf00"; - context.strokeStyle = "red"; - tubColor = "black"; - } - else { - context.fillStyle = "#1a8cff"; - context.strokeStyle = "#80ffe5"; - tubColor = "white"; + + function drawBubble(r, c) { + bubbleX = c * tileSize; + var grd = context.createRadialGradient(bubbleX, r * tileSize, 0, bubbleX, r * tileSize, tileSize); + grd.addColorStop(0, "rgba(255,255,255,.9)"); + grd.addColorStop(1, "rgba(255,255,255,.2)"); + context.fillStyle = grd; + context.lineWidth = .5; + context.strokeStyle = "rgba(200,200,200,.2)"; + + context.beginPath(); + context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, tileSize / 2, 0, 2 * Math.PI); + context.fill(); + context.stroke(); } - roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); - - context.lineWidth = 3; - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.1, c*tileSize+tileSize/3, r*tileSize+tileSize*.1, c*tileSize+tileSize/2, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.3, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.3, c*tileSize+tileSize, r*tileSize+tileSize*.2); - context.moveTo(c*tileSize, r*tileSize+tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.3, c*tileSize+tileSize/3, r*tileSize+tileSize*.3, c*tileSize+tileSize/2, r*tileSize+tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.5, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.5, c*tileSize+tileSize, r*tileSize+tileSize*.4); - context.moveTo(c*tileSize, r*tileSize+tileSize*.6); - context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.5, c*tileSize+tileSize/3, r*tileSize+tileSize*.5, c*tileSize+tileSize/2, r*tileSize+tileSize*.6); - context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.7, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.7, c*tileSize+tileSize, r*tileSize+tileSize*.6); - context.moveTo(c*tileSize, r*tileSize+tileSize*.8); - context.bezierCurveTo(c*tileSize+tileSize/6, r*tileSize+tileSize*.7, c*tileSize+tileSize/3, r*tileSize+tileSize*.7, c*tileSize+tileSize/2, r*tileSize+tileSize*.8); - context.bezierCurveTo(c*tileSize+tileSize*2/3, r*tileSize+tileSize*.9, c*tileSize+tileSize*5/6, r*tileSize+tileSize*.9, c*tileSize+tileSize, r*tileSize+tileSize*.8); - context.stroke(); - - context.fillStyle = tubColor; - if(!isOccupied(-1,0)) { - if(isOccupied(-1,-1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize-tileSize*.2, tileSize*.2, tileSize*1.2, 0, true, false); - else roundRect(context, c*tileSize-tileSize*.1, r*tileSize, tileSize*.2, tileSize, 0, true, false); + + function drawLiquid(r, c, type, adjacentTiles) { + newLiquid(r, c, type, isSameLiquid); + + function isSameLiquid(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === type; + } } - if(!isOccupied(1,0)) roundRect(context, c*tileSize+tileSize*.9, r*tileSize, tileSize*.2, tileSize, 0, true, false); - if(!isOccupied(0,1)) { - if(isOccupied(-1,1) && !isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); - else if(!isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize*1.3, tileSize*.2, 0, true, false); - else if(isOccupied(-1,1) && isOccupied(1,1)) roundRect(context, c*tileSize-tileSize*.1, r*tileSize+tileSize*.8, tileSize*1.1, tileSize*.2, 0, true, false); - else roundRect(context, c*tileSize, r*tileSize+tileSize*.8, tileSize, tileSize*.2, 0, true, false); + + function newLiquid(r, c, type, isOccupied) { + context.save(); + var tubColor; + if (type == LAVA) { + context.fillStyle = "#ffbf00"; + context.strokeStyle = "red"; + tubColor = "black"; + } + else { + context.fillStyle = "#1a8cff"; + context.strokeStyle = "#80ffe5"; + tubColor = "white"; + } + roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 0, true, false); + + context.lineWidth = 3; + context.beginPath(); + context.moveTo(c * tileSize, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .1, c * tileSize + tileSize / 3, r * tileSize + tileSize * .1, c * tileSize + tileSize / 2, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .3, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .3, c * tileSize + tileSize, r * tileSize + tileSize * .2); + context.moveTo(c * tileSize, r * tileSize + tileSize * .4); + context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .3, c * tileSize + tileSize / 3, r * tileSize + tileSize * .3, c * tileSize + tileSize / 2, r * tileSize + tileSize * .4); + context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .5, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .5, c * tileSize + tileSize, r * tileSize + tileSize * .4); + context.moveTo(c * tileSize, r * tileSize + tileSize * .6); + context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .5, c * tileSize + tileSize / 3, r * tileSize + tileSize * .5, c * tileSize + tileSize / 2, r * tileSize + tileSize * .6); + context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .7, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .7, c * tileSize + tileSize, r * tileSize + tileSize * .6); + context.moveTo(c * tileSize, r * tileSize + tileSize * .8); + context.bezierCurveTo(c * tileSize + tileSize / 6, r * tileSize + tileSize * .7, c * tileSize + tileSize / 3, r * tileSize + tileSize * .7, c * tileSize + tileSize / 2, r * tileSize + tileSize * .8); + context.bezierCurveTo(c * tileSize + tileSize * 2 / 3, r * tileSize + tileSize * .9, c * tileSize + tileSize * 5 / 6, r * tileSize + tileSize * .9, c * tileSize + tileSize, r * tileSize + tileSize * .8); + context.stroke(); + + context.fillStyle = tubColor; + if (!isOccupied(-1, 0)) { + if (isOccupied(-1, -1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize - tileSize * .2, tileSize * .2, tileSize * 1.2, 0, true, false); + else roundRect(context, c * tileSize - tileSize * .1, r * tileSize, tileSize * .2, tileSize, 0, true, false); + } + if (!isOccupied(1, 0)) roundRect(context, c * tileSize + tileSize * .9, r * tileSize, tileSize * .2, tileSize, 0, true, false); + if (!isOccupied(0, 1)) { + if (isOccupied(-1, 1) && !isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize + tileSize * .8, tileSize * 1.1, tileSize * .2, 0, true, false); + else if (!isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize, r * tileSize + tileSize * .8, tileSize * 1.3, tileSize * .2, 0, true, false); + else if (isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize + tileSize * .8, tileSize * 1.1, tileSize * .2, 0, true, false); + else roundRect(context, c * tileSize, r * tileSize + tileSize * .8, tileSize, tileSize * .2, 0, true, false); + } + context.restore(); } - context.restore(); -} - function drawLift(r, c, isFixed) { + function drawLift(r, c, isFixed) { context.lineWidth = .5; context.strokeStyle = "#777"; var strokeBool = false; - if(!isFixed) { + if (!isFixed) { context.fillStyle = "#e68a00"; - roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); + roundRect(context, c * tileSize + tileSize * .05, r * tileSize + tileSize, tileSize * .9, tileSize * .2, 2, true, strokeBool); context.fillStyle = "#cc0000"; - roundRect(context, c*tileSize+tileSize*.3, r*tileSize+tileSize*.8, tileSize*.4, tileSize*.2, {tl:2, tr:2}, true, strokeBool); + roundRect(context, c * tileSize + tileSize * .3, r * tileSize + tileSize * .8, tileSize * .4, tileSize * .2, { tl: 2, tr: 2 }, true, strokeBool); } - else if(isFixed) { + else if (isFixed) { context.fillStyle = "#e68a00"; - roundRect(context, c*tileSize+tileSize*.05, r*tileSize+tileSize*.8, tileSize*.9, tileSize*.2, 2, true, strokeBool); - roundRect(context, c*tileSize+tileSize*.05, r*tileSize, tileSize*.9, tileSize*.2, 2, true, strokeBool); - + roundRect(context, c * tileSize + tileSize * .05, r * tileSize + tileSize * .8, tileSize * .9, tileSize * .2, 2, true, strokeBool); + roundRect(context, c * tileSize + tileSize * .05, r * tileSize, tileSize * .9, tileSize * .2, 2, true, strokeBool); + context.fillStyle = "#333"; - + context.beginPath(); - context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize+tileSize*.45); - context.bezierCurveTo(c*tileSize+tileSize*.16,r*tileSize+tileSize*.45,c*tileSize+tileSize*.16,r*tileSize+tileSize*.55,c*tileSize+tileSize*.2,r*tileSize+tileSize*.55); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.8); + context.moveTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .8); + context.lineTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .5); + context.lineTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize * .7, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize * .2, r * tileSize + tileSize * .45); + context.bezierCurveTo(c * tileSize + tileSize * .16, r * tileSize + tileSize * .45, c * tileSize + tileSize * .16, r * tileSize + tileSize * .55, c * tileSize + tileSize * .2, r * tileSize + tileSize * .55); + context.lineTo(c * tileSize + tileSize * .7, r * tileSize + tileSize * .8); + context.lineTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .8); context.closePath(); context.fill(); - + context.beginPath(); - context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.7, r*tileSize+tileSize*.5); - context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize+tileSize*.45); - context.bezierCurveTo(c*tileSize+tileSize*.84,r*tileSize+tileSize*.45,c*tileSize+tileSize*.84,r*tileSize+tileSize*.55,c*tileSize+tileSize*.8,r*tileSize+tileSize*.55); - context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.8); - context.lineTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.8); + context.moveTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .8); + context.lineTo(c * tileSize + tileSize * .7, r * tileSize + tileSize * .5); + context.lineTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize * .8, r * tileSize + tileSize * .45); + context.bezierCurveTo(c * tileSize + tileSize * .84, r * tileSize + tileSize * .45, c * tileSize + tileSize * .84, r * tileSize + tileSize * .55, c * tileSize + tileSize * .8, r * tileSize + tileSize * .55); + context.lineTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .8); + context.lineTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .8); context.closePath(); context.fill(); - + /*context.beginPath(); context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.9); context.lineTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.5); @@ -2873,7 +2852,7 @@ function newLiquid(r, c, type, isOccupied){ context.closePath(); context.fill();*/ } - + /*var grd = context.createLinearGradient(c*tileSize, r*tileSize, (c+1)*tileSize, (r+1)*tileSize); grd.addColorStop(0, "rgba(255,255,255,.6)"); grd.addColorStop(.1, "rgba(255,255,255,.7)"); @@ -2979,37 +2958,37 @@ function newLiquid(r, c, type, isOccupied){ context.lineTo(c*tileSize+tileSize*.45, r*tileSize+tileSize*.2); context.stroke(); }*/ - } - - function drawWall(r, c, adjacentTiles) { //GOOBY - //drawRect(r, c, "#976537"); - drawTileNew(r, c, isWall, 0.2, material); - drawTileOutlines(r, c, isWall, 0.2, curlyOutline); - context.save(); - if(curlyOutline) drawBushes(r, c, isWall); - context.restore(); - context.fillStyle = "#895C33"; // dirt edge - //drawTileOutlines(r, c, isWall, 0.2, false); - - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; } - } - - function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle){ + + function drawWall(r, c, adjacentTiles) { //GOOBY + //drawRect(r, c, "#976537"); + drawTileNew(r, c, isWall, 0.2, material); + drawTileOutlines(r, c, isWall, 0.2, curlyOutline); + context.save(); + if (curlyOutline) drawBushes(r, c, isWall); + context.restore(); + context.fillStyle = "#895C33"; // dirt edge + //drawTileOutlines(r, c, isWall, 0.2, false); + + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } + } + + function drawTileNew(r, c, isOccupied, outlineThickness, fillStyle) { context.fillStyle = fillStyle; - if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10,br:10}, true, false); - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,bl:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10,tr:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10,br:10}, true, false); - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {bl:10}, true, false); - else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {br:10}, true, false); - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tl:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, {tr:10}, true, false); - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 10, true, false); - else roundRect(context, c*tileSize, r*tileSize, tileSize, tileSize, 0, true, false); - + if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { bl: 10, br: 10 }, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tr: 10, br: 10 }, true, false); + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { bl: 10 }, true, false); + else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { br: 10 }, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tl: 10 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, { tr: 10 }, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 10, true, false); + else roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 0, true, false); + /*var randomSpot = Math.floor(Math.random() * 5); //random spots on dirt var randomColor = Math.floor(Math.random() * 5); context.beginPath(); @@ -3027,1062 +3006,1063 @@ function newLiquid(r, c, type, isOccupied){ } context.stroke();*/ } - - function drawCurves(r, c, adjacentTiles){ + + function drawCurves(r, c, adjacentTiles) { drawCurves2(r, c, isWall, material); - + function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; } } - - function drawCurves2(r, c, isOccupied, material){ + + function drawCurves2(r, c, isOccupied, material) { context.fillStyle = material; - if(isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { - context.fillRect((c+1)*tileSize, (r+1)*tileSize, tileSize/6, tileSize/6); + if (isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(1, 1) && curlyOutline) { + context.fillRect((c + 1) * tileSize, (r + 1) * tileSize, tileSize / 6, tileSize / 6); //context.globalCompositeOperation = "destination-out"; context.beginPath(); - context.arc((c+1)*tileSize+tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); + context.arc((c + 1) * tileSize + tileSize / 6, (r + 1) * tileSize + tileSize / 6, tileSize / 6, 0, 2 * Math.PI); context.closePath(); - + var bgColor; - if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*')+2, background.length); + if ((c + r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*') + 2, background.length); var r1, r2, b1, b2, g1, g2; - r1 = bgColor.substr(5, bgColor.indexOf(",")-5); - g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); - b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); - var shade = (r+1)*.03+.5; - if(shade>1) + r1 = bgColor.substr(5, bgColor.indexOf(",") - 5); + g1 = bgColor.substr(bgColor.indexOf(",") + 1, bgColor.indexOf(",") - 4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",") + 1) + 1, bgColor.indexOf(",") - 4); + var shade = (r + 1) * .03 + .5; + if (shade > 1) shade = 1; - r2 = 255 + (r1-255) * shade; - g2 = 255 + (g1-255) * shade; - b2 = 255 + (b1-255) * shade; + r2 = 255 + (r1 - 255) * shade; + g2 = 255 + (g1 - 255) * shade; + b2 = 255 + (b1 - 255) * shade; context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; context.fill(); - context.globalCompositeOperation = "source-over"; + context.globalCompositeOperation = "source-over"; } - if(isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1) && curlyOutline) { - context.fillRect(c*tileSize-tileSize/6, (r+1)*tileSize, tileSize/6, tileSize/6); + if (isOccupied(-1, 0) && isOccupied(0, 1) && !isOccupied(-1, 1) && curlyOutline) { + context.fillRect(c * tileSize - tileSize / 6, (r + 1) * tileSize, tileSize / 6, tileSize / 6); //context.globalCompositeOperation = "destination-out"; context.beginPath(); - context.arc(c*tileSize-tileSize/6, (r+1)*tileSize+tileSize/6, tileSize/6, 0, 2*Math.PI); + context.arc(c * tileSize - tileSize / 6, (r + 1) * tileSize + tileSize / 6, tileSize / 6, 0, 2 * Math.PI); context.closePath(); - + var bgColor; - if((c+r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*')+2, background.length); + if ((c + r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); + else bgColor = background.substr(background.indexOf('*') + 2, background.length); var r1, r2, b1, b2, g1, g2; - r1 = bgColor.substr(5, bgColor.indexOf(",")-5); - g1 = bgColor.substr(bgColor.indexOf(",")+1, bgColor.indexOf(",")-4); - b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",")+1)+1, bgColor.indexOf(",")-4); - var shade = (r+1)*.03+.5; - if(shade>1) + r1 = bgColor.substr(5, bgColor.indexOf(",") - 5); + g1 = bgColor.substr(bgColor.indexOf(",") + 1, bgColor.indexOf(",") - 4); + b1 = bgColor.substr(bgColor.indexOf(",", bgColor.indexOf(",") + 1) + 1, bgColor.indexOf(",") - 4); + var shade = (r + 1) * .03 + .5; + if (shade > 1) shade = 1; - r2 = 255 + (r1-255) * shade; - g2 = 255 + (g1-255) * shade; - b2 = 255 + (b1-255) * shade; + r2 = 255 + (r1 - 255) * shade; + g2 = 255 + (g1 - 255) * shade; + b2 = 255 + (b1 - 255) * shade; context.fillStyle = "rgb(" + r2 + ", " + g2 + ", " + b2 + ")"; context.fill(); context.globalCompositeOperation = "source-over"; } } - - function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { //Gooby - if(surface != "rainbow") { - context.fillStyle = surface; - } - else{ - context.fillStyle = "white"; - var mod = (r+c) % 17; - switch(mod){ - case 0: context.fillStyle = "#ff004c"; break; - case 1: context.fillStyle = "#e30000"; break; - case 2: context.fillStyle = "#ff4c00"; break; - case 3: context.fillStyle = "#ff9900"; break; - case 4: context.fillStyle = "#ffe500"; break; - case 5: context.fillStyle = "#cbff00"; break; - case 6: context.fillStyle = "#7fff00"; break; - case 7: context.fillStyle = "#00ff19"; break; - case 8: context.fillStyle = "#00ff66"; break; - case 9: context.fillStyle = "#00ffb2"; break; - case 10: context.fillStyle = "#00ffff"; break; - case 11: context.fillStyle = "#00b2ff"; break; - case 12: context.fillStyle = "#3200ff"; break; - case 13: context.fillStyle = "#5702c6"; break; - case 14: context.fillStyle = "#cc00ff"; break; - case 15: context.fillStyle = "#ff00e5"; break; - case 16: context.fillStyle = "#ff0098"; break; - } - } - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - var complementPixels = (1 - 2 * outlineThickness) * tileSize; - - if (curlyOutline && !isOccupied(0, -1)){ - if(!isOccupied(-1, 0) && isOccupied(1, 0)){ - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.1, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.9, r*tileSize+tileSize*.4, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize); - context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); - context.closePath(); + + function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { //Gooby + if (surface != "rainbow") { + context.fillStyle = surface; } - else if(isOccupied(-1, 0) && !isOccupied(1, 0)){ - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.95, r*tileSize+tileSize*.3, c*tileSize+tileSize*.7, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.65, r*tileSize+tileSize*.4, c*tileSize+tileSize*.4, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.1, r*tileSize+tileSize*.4, c*tileSize, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize+tileSize*.8, r*tileSize); - context.bezierCurveTo((c+1)*tileSize+tileSize*.2, r*tileSize-tileSize*.05, (c+1)*tileSize+tileSize*.15, r*tileSize+tileSize*.5, (c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.25); - context.closePath(); + else { + context.fillStyle = "white"; + var mod = (r + c) % 17; + switch (mod) { + case 0: context.fillStyle = "#ff004c"; break; + case 1: context.fillStyle = "#e30000"; break; + case 2: context.fillStyle = "#ff4c00"; break; + case 3: context.fillStyle = "#ff9900"; break; + case 4: context.fillStyle = "#ffe500"; break; + case 5: context.fillStyle = "#cbff00"; break; + case 6: context.fillStyle = "#7fff00"; break; + case 7: context.fillStyle = "#00ff19"; break; + case 8: context.fillStyle = "#00ff66"; break; + case 9: context.fillStyle = "#00ffb2"; break; + case 10: context.fillStyle = "#00ffff"; break; + case 11: context.fillStyle = "#00b2ff"; break; + case 12: context.fillStyle = "#3200ff"; break; + case 13: context.fillStyle = "#5702c6"; break; + case 14: context.fillStyle = "#cc00ff"; break; + case 15: context.fillStyle = "#ff00e5"; break; + case 16: context.fillStyle = "#ff0098"; break; + } } - else if(!isOccupied(-1, 0) && !isOccupied(1, 0)){ - context.beginPath(); - context.moveTo(c*tileSize+tileSize*.9, r*tileSize-tileSize*0); - context.lineTo(c*tileSize+tileSize*.2, r*tileSize); - context.bezierCurveTo(c*tileSize-tileSize*.2, r*tileSize-tileSize*.05, c*tileSize-tileSize*.15, r*tileSize+tileSize*.5, c*tileSize+tileSize*.1, r*tileSize+tileSize*.25); - context.bezierCurveTo(c*tileSize+tileSize*.05, r*tileSize+tileSize*.3, c*tileSize+tileSize*.3, r*tileSize+tileSize*.4, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.4, c*tileSize+tileSize*.6, r*tileSize+tileSize*.4, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.3, c*tileSize+tileSize*.8, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.2); - context.bezierCurveTo((c+1)*tileSize-tileSize*.1, r*tileSize+tileSize*.4, (c+1)*tileSize+tileSize*.3, r*tileSize+tileSize*.3, (c+1)*tileSize, r*tileSize+tileSize*.02); - context.closePath(); + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + var complementPixels = (1 - 2 * outlineThickness) * tileSize; + + if (curlyOutline && !isOccupied(0, -1)) { + if (!isOccupied(-1, 0) && isOccupied(1, 0)) { + context.beginPath(); + context.moveTo(c * tileSize + tileSize * .1, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .05, r * tileSize + tileSize * .3, c * tileSize + tileSize * .3, r * tileSize + tileSize * .4, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .35, r * tileSize + tileSize * .4, c * tileSize + tileSize * .6, r * tileSize + tileSize * .4, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .75, r * tileSize + tileSize * .3, c * tileSize + tileSize * .9, r * tileSize + tileSize * .4, c * tileSize + tileSize * 1, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize, r * tileSize); + context.lineTo(c * tileSize + tileSize * .2, r * tileSize); + context.bezierCurveTo(c * tileSize - tileSize * .2, r * tileSize - tileSize * .05, c * tileSize - tileSize * .15, r * tileSize + tileSize * .5, c * tileSize + tileSize * .1, r * tileSize + tileSize * .25); + context.closePath(); + } + else if (isOccupied(-1, 0) && !isOccupied(1, 0)) { + context.beginPath(); + context.moveTo(c * tileSize + tileSize * .9, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .95, r * tileSize + tileSize * .3, c * tileSize + tileSize * .7, r * tileSize + tileSize * .4, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .65, r * tileSize + tileSize * .4, c * tileSize + tileSize * .4, r * tileSize + tileSize * .4, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .3, r * tileSize + tileSize * .3, c * tileSize + tileSize * .1, r * tileSize + tileSize * .4, c * tileSize, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize, r * tileSize); + context.lineTo(c * tileSize + tileSize * .8, r * tileSize); + context.bezierCurveTo((c + 1) * tileSize + tileSize * .2, r * tileSize - tileSize * .05, (c + 1) * tileSize + tileSize * .15, r * tileSize + tileSize * .5, (c + 1) * tileSize - tileSize * .1, r * tileSize + tileSize * .25); + context.closePath(); + } + else if (!isOccupied(-1, 0) && !isOccupied(1, 0)) { + context.beginPath(); + context.moveTo(c * tileSize + tileSize * .9, r * tileSize - tileSize * 0); + context.lineTo(c * tileSize + tileSize * .2, r * tileSize); + context.bezierCurveTo(c * tileSize - tileSize * .2, r * tileSize - tileSize * .05, c * tileSize - tileSize * .15, r * tileSize + tileSize * .5, c * tileSize + tileSize * .1, r * tileSize + tileSize * .25); + context.bezierCurveTo(c * tileSize + tileSize * .05, r * tileSize + tileSize * .3, c * tileSize + tileSize * .3, r * tileSize + tileSize * .4, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .35, r * tileSize + tileSize * .4, c * tileSize + tileSize * .6, r * tileSize + tileSize * .4, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .75, r * tileSize + tileSize * .3, c * tileSize + tileSize * .8, r * tileSize + tileSize * .4, c * tileSize + tileSize * .9, r * tileSize + tileSize * .2); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .1, r * tileSize + tileSize * .4, (c + 1) * tileSize + tileSize * .3, r * tileSize + tileSize * .3, (c + 1) * tileSize, r * tileSize + tileSize * .02); + context.closePath(); + } + else { + context.beginPath(); + context.moveTo(c * tileSize, r * tileSize); + context.lineTo(c * tileSize, r * tileSize + tileSize * .15); + context.bezierCurveTo(c * tileSize + tileSize * 0, r * tileSize + tileSize * .4, c * tileSize + tileSize * .3, r * tileSize + tileSize * .3, c * tileSize + tileSize * .33, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .35, r * tileSize + tileSize * .3, c * tileSize + tileSize * .6, r * tileSize + tileSize * .3, c * tileSize + tileSize * .67, r * tileSize + tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .75, r * tileSize + tileSize * .4, c * tileSize + tileSize * .9, r * tileSize + tileSize * .3, c * tileSize + tileSize * 1, r * tileSize + tileSize * .2); + context.lineTo(c * tileSize + tileSize, r * tileSize); + context.closePath(); + } + context.fill(); } - else{ - context.beginPath(); - context.moveTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize+tileSize*.15); - context.bezierCurveTo(c*tileSize+tileSize*0, r*tileSize+tileSize*.4, c*tileSize+tileSize*.3, r*tileSize+tileSize*.3, c*tileSize+tileSize*.33, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.35, r*tileSize+tileSize*.3, c*tileSize+tileSize*.6, r*tileSize+tileSize*.3, c*tileSize+tileSize*.67, r*tileSize+tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.75, r*tileSize+tileSize*.4, c*tileSize+tileSize*.9, r*tileSize+tileSize*.3, c*tileSize+tileSize*1, r*tileSize+tileSize*.2); - context.lineTo(c*tileSize+tileSize, r*tileSize); - context.closePath(); + else if (!curlyOutline && !isOccupied(0, -1)) { + context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + } - context.fill(); + if (!curlyOutline && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(1, -1)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(1, 1)) context.fillRect((c + complement) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); + if (!curlyOutline && !isOccupied(0, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, tileSize, outlinePixels); + if (!curlyOutline && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!curlyOutline && !isOccupied(1, 0)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); } - else if(!curlyOutline && !isOccupied(0, -1)){ context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - - } - if (!curlyOutline && !isOccupied(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!curlyOutline && !isOccupied( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (!curlyOutline && !isOccupied(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!curlyOutline && !isOccupied( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); - } - - function drawBushes(r, c, isOccupied){ - if(!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)){ + + function drawBushes(r, c, isOccupied) { + if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(1, -1)) { /*context.shadowColor = "#666"; context.shadowOffsetX = -.5; context.shadowOffsetY = -.5; context.shadowBlur = 1;*/ - + context.beginPath(); - context.moveTo((c+1)*tileSize, r*tileSize); - context.lineTo((c+1)*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); - context.lineTo((c+1)*tileSize, r*tileSize); + context.moveTo((c + 1) * tileSize, r * tileSize); + context.lineTo((c + 1) * tileSize, r * tileSize - tileSize * .4); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .1, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .2); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .3, r * tileSize - tileSize * .2, (c + 1) * tileSize - tileSize * .4, r * tileSize - tileSize * .1, (c + 1) * tileSize - tileSize * .3, r * tileSize); + context.lineTo((c + 1) * tileSize, r * tileSize); context.closePath(); context.fill(); - + context.beginPath(); - context.moveTo((c+1)*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo((c+1)*tileSize-tileSize*.1,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2,r*tileSize-tileSize*.4,(c+1)*tileSize-tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo((c+1)*tileSize-tileSize*.3,r*tileSize-tileSize*.2,(c+1)*tileSize-tileSize*.4,r*tileSize-tileSize*.1,(c+1)*tileSize-tileSize*.3, r*tileSize); + context.moveTo((c + 1) * tileSize, r * tileSize - tileSize * .4); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .1, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .4, (c + 1) * tileSize - tileSize * .2, r * tileSize - tileSize * .2); + context.bezierCurveTo((c + 1) * tileSize - tileSize * .3, r * tileSize - tileSize * .2, (c + 1) * tileSize - tileSize * .4, r * tileSize - tileSize * .1, (c + 1) * tileSize - tileSize * .3, r * tileSize); } - - if(!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)){ + + if (!isOccupied(0, -1) && isOccupied(-1, 0) && isOccupied(-1, -1)) { /*context.shadowColor = "#666"; context.shadowOffsetX = .5; context.shadowOffsetY = -.5; context.shadowBlur = 1;*/ - + context.beginPath(); - context.moveTo(c*tileSize, r*tileSize); - context.lineTo(c*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); - context.lineTo(c*tileSize, r*tileSize); + context.moveTo(c * tileSize, r * tileSize); + context.lineTo(c * tileSize, r * tileSize - tileSize * .4); + context.bezierCurveTo(c * tileSize + tileSize * .1, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .3, r * tileSize - tileSize * .2, c * tileSize + tileSize * .4, r * tileSize - tileSize * .1, c * tileSize + tileSize * .3, r * tileSize); + context.lineTo(c * tileSize, r * tileSize); context.closePath(); context.fill(); - + context.restore(); - + context.beginPath(); - context.moveTo(c*tileSize, r*tileSize-tileSize*.4); - context.bezierCurveTo(c*tileSize+tileSize*.1,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2,r*tileSize-tileSize*.4,c*tileSize+tileSize*.2, r*tileSize-tileSize*.2); - context.bezierCurveTo(c*tileSize+tileSize*.3,r*tileSize-tileSize*.2,c*tileSize+tileSize*.4,r*tileSize-tileSize*.1,c*tileSize+tileSize*.3, r*tileSize); + context.moveTo(c * tileSize, r * tileSize - tileSize * .4); + context.bezierCurveTo(c * tileSize + tileSize * .1, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .4, c * tileSize + tileSize * .2, r * tileSize - tileSize * .2); + context.bezierCurveTo(c * tileSize + tileSize * .3, r * tileSize - tileSize * .2, c * tileSize + tileSize * .4, r * tileSize - tileSize * .1, c * tileSize + tileSize * .3, r * tileSize); /*context.strokeStyle = "#7dff1a"; - context.stroke();*/ + context.stroke();*/ } } - - function drawSpikes(r, c, adjacentTiles) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = spikeColors[0]; - - context.beginPath(); - context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes - context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.45, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.55, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.75, y + tileSize * 0.3); - - context.moveTo(x + tileSize * 0.7, y + tileSize * 0.25); //right spikes - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.45); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.55); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.75); - - context.moveTo(x + tileSize * 0.75, y + tileSize * 0.7); //bottom spikes - context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.55, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.45, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.25, y + tileSize * 0.7); - - context.moveTo(x + tileSize * 0.3, y + tileSize * 0.75); //left spikes - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.55); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.45); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); - context.closePath(); - - /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ - context.fill(); - drawSpikeSupports(r, c, isSpike, isWall); - - function isSpike(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === SPIKE; - } - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; + + function drawSpikes(r, c, adjacentTiles) { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = spikeColors[0]; + + context.beginPath(); + context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes + context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.45, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.55, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.75, y + tileSize * 0.3); + + context.moveTo(x + tileSize * 0.7, y + tileSize * 0.25); //right spikes + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.45); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.55); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.75); + + context.moveTo(x + tileSize * 0.75, y + tileSize * 0.7); //bottom spikes + context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.55, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.45, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.25, y + tileSize * 0.7); + + context.moveTo(x + tileSize * 0.3, y + tileSize * 0.75); //left spikes + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.55); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.45); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); + context.closePath(); + + /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ + context.fill(); + drawSpikeSupports(r, c, isSpike, isWall); + + function isSpike(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === SPIKE; + } + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } } - } - - function drawSpikeSupports(r, c, isOccupied, canConnect){ + + function drawSpikeSupports(r, c, isOccupied, canConnect) { var boltBool = false; var occupiedCount = 0; - if(canConnect(0, 1)){ + if (canConnect(0, 1)) { context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize+(tileSize*.3), r*tileSize+(tileSize*.8), tileSize*.4, tileSize*.4); + context.fillRect(c * tileSize + (tileSize * .3), r * tileSize + (tileSize * .8), tileSize * .4, tileSize * .4); boltBool = true; } - if(canConnect(0, -1) && !canConnect(0, 1)){ - if(!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(1, -1)){} - else{ + if (canConnect(0, -1) && !canConnect(0, 1)) { + if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(1, -1)) { } + else { context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize+(tileSize*.3), r*tileSize, tileSize*.4, tileSize*.4); + context.fillRect(c * tileSize + (tileSize * .3), r * tileSize, tileSize * .4, tileSize * .4); boltBool = true; } } - if(canConnect(-1, 0) && !canConnect(0, 1)){ - if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(-1, 1)){} - else{ + if (canConnect(-1, 0) && !canConnect(0, 1)) { + if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(-1, -1) && canConnect(-1, 1)) { } + else { context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize, r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); + context.fillRect(c * tileSize, r * tileSize + (tileSize * .3), tileSize * .4, tileSize * .4); boltBool = true; } } - if(canConnect(1, 0) && !canConnect(0, 1)){ - if(isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(1, -1) && canConnect(1, 1)){} - else{ + if (canConnect(1, 0) && !canConnect(0, 1)) { + if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0) && canConnect(1, -1) && canConnect(1, 1)) { } + else { context.fillStyle = spikeColors[1]; - context.fillRect(c*tileSize+(tileSize*.8), r*tileSize+(tileSize*.3), tileSize*.4, tileSize*.4); + context.fillRect(c * tileSize + (tileSize * .8), r * tileSize + (tileSize * .3), tileSize * .4, tileSize * .4); boltBool = true; } } - + context.fillStyle = spikeColors[2]; - if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING ONE - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4,br:4}, true, false); + if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING ONE + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, { bl: 4, br: 4 }, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize, tileSize*.6, {tl:4,bl:4}, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize, tileSize * .6, { tl: 4, bl: 4 }, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4,tr:4}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, { tl: 4, tr: 4 }, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4,br:4}, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { tr: 4, br: 4 }, true, false); boltBool = true; } - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (CORNERS) - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {bl:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {bl:4}, true, false); - if(!canConnect(1, -1)) boltBool = true; + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING TWO (CORNERS) + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, { bl: 4 }, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { bl: 4 }, true, false); + if (!canConnect(1, -1)) boltBool = true; + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { br: 4 }, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, { br: 4 }, true, false); + if (!canConnect(-1, -1)) boltBool = true; } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {br:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, {br:4}, true, false); - if(!canConnect(-1, -1)) boltBool = true; + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { tl: 4 }, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, { tl: 4 }, true, false); + if (!canConnect(1, 1)) boltBool = true; } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tl:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tl:4}, true, false); - if(!canConnect(1, 1)) boltBool = true; - } - else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, {tr:4}, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, {tr:4}, true, false); - if(!canConnect(-1, 1)) boltBool = true; - } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING TWO (OPPOSITES) - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + else if (!isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, { tr: 4 }, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, { tr: 4 }, true, false); + if (!canConnect(-1, 1)) boltBool = true; } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); + else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING TWO (OPPOSITES) + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); } - else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)){ //TOUCHING THREE - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize*.8, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize*.8, tileSize*.6, 0, true, false); + else if (!isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && !isOccupied(-1, 0)) { //TOUCHING THREE + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, 0, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && isOccupied(1, 0) && !isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize * .8, 0, true, false); + boltBool = true; + } + else if (isOccupied(0, -1) && !isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize * .8, tileSize * .6, 0, true, false); + boltBool = true; + } + else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .8, 0, true, false); boltBool = true; } - else if (!isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.8, 0, true, false); - boltBool = true; - } - else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)){ //TOUCHING FOUR - roundRect(context, c*tileSize, r*tileSize+(tileSize*.2), tileSize, tileSize*.6, 0, true, false); - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize, tileSize*.6, tileSize, 0, true, false); + else if (isOccupied(0, -1) && isOccupied(1, 0) && isOccupied(0, 1) && isOccupied(-1, 0)) { //TOUCHING FOUR + roundRect(context, c * tileSize, r * tileSize + (tileSize * .2), tileSize, tileSize * .6, 0, true, false); + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize, tileSize * .6, tileSize, 0, true, false); //boltBool = true; } - else{ - roundRect(context, c*tileSize+(tileSize*.2), r*tileSize+(tileSize*.2), tileSize*.6, tileSize*.6, 0, true, false); + else { + roundRect(context, c * tileSize + (tileSize * .2), r * tileSize + (tileSize * .2), tileSize * .6, tileSize * .6, 0, true, false); boltBool = true; } - + if (boltBool) drawBolt(r, c); } - - function drawBolt(r, c){ + + function drawBolt(r, c) { context.strokeStyle = spikeColors[3]; context.beginPath(); - context.arc(c*tileSize+(tileSize*.55), r*tileSize+(tileSize*.45), 4, -.7*Math.PI, .2*Math.PI); - context.lineTo(c*tileSize+(tileSize*.45),r*tileSize+(tileSize*.35)); + context.arc(c * tileSize + (tileSize * .55), r * tileSize + (tileSize * .45), 4, -.7 * Math.PI, .2 * Math.PI); + context.lineTo(c * tileSize + (tileSize * .45), r * tileSize + (tileSize * .35)); context.closePath(); context.fillStyle = spikeColors[3]; context.fill(); context.stroke(); - + context.beginPath(); - context.moveTo(c*tileSize+(tileSize*.43),r*tileSize+(tileSize*.47)); - context.arc(c*tileSize+(tileSize*.48), r*tileSize+(tileSize*.52), 4, .2*Math.PI, -.75*Math.PI); + context.moveTo(c * tileSize + (tileSize * .43), r * tileSize + (tileSize * .47)); + context.arc(c * tileSize + (tileSize * .48), r * tileSize + (tileSize * .52), 4, .2 * Math.PI, -.75 * Math.PI); //context.lineTo(c*tileSize+(tileSize*.4),r*tileSize+(tileSize*.6)); context.closePath(); context.fillStyle = spikeColors[3]; context.fill(); context.stroke(); } - - function drawConnector(context, r1, c1, r2, c2, color) { - // either r1 and r2 or c1 and c2 must be equal - if (r1 > r2 || c1 > c2) { - var rTmp = r1; - var cTmp = c1; - r1 = r2; - c1 = c2; - r2 = rTmp; - c2 = cTmp; - } - var xLo = (c1 + 0.3) * tileSize; - var yLo = (r1 + 0.3) * tileSize; - var xHi = (c2 + 0.45) * tileSize; - var yHi = (r2 + 0.45) * tileSize; - context.fillStyle = color; - context.fillRect(xLo+.15*tileSize, yLo+.15*tileSize, xHi - xLo, yHi - yLo); - } - function drawBlock(block) { - var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); - var rowcols = block.locations.map(function(location) { - return getRowcol(level, location); - }); - rowcols.forEach(function(rowcol) { - var r = rowcol.r + animationDisplacementRowcol.r; - var c = rowcol.c + animationDisplacementRowcol.c; - context.fillStyle = blockColors[0][block.id % blockColors[0].length]; - var outlineThickness = .2; - - var complement = 1 - outlineThickness; - var outlinePixels = outlineThickness * tileSize; - if (!isAlsoThisBlock(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock( 1, -1)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock(-1, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock( 1, 1)) context.fillRect((c+complement) * tileSize, (r+complement) * tileSize, outlinePixels, outlinePixels); - if (!isAlsoThisBlock( 0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); - if (!isAlsoThisBlock( 0, 1)) context.fillRect((c) * tileSize, (r+complement) * tileSize, tileSize, outlinePixels); - if (!isAlsoThisBlock(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); - if (!isAlsoThisBlock( 1, 0)) context.fillRect((c+complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); - - function isAlsoThisBlock(dc, dr) { - for (var i = 0; i < rowcols.length; i++) { - var otherRowcol = rowcols[i]; - if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; + + function drawConnector(context, r1, c1, r2, c2, color) { + // either r1 and r2 or c1 and c2 must be equal + if (r1 > r2 || c1 > c2) { + var rTmp = r1; + var cTmp = c1; + r1 = r2; + c1 = c2; + r2 = rTmp; + c2 = cTmp; } - return false; - } - }); - } - function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { - var cx = (c + 0.5) * tileSize; - var cy = (r + 0.5) * tileSize; - context.fillStyle = fillStyle; - context.beginPath(); - context.moveTo(cx, cy); - context.arc(cx, cy, radiusFactor * tileSize/2, quadrant * Math.PI/2, (quadrant + 1) * Math.PI/2); - context.fill(); - } - function drawDiamond(r, c, fillStyle) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = fillStyle; - roundRect(context, x, y, tileSize, tileSize, 10, true, false); - } - function drawCircle(r, c, radiusFactor, fillStyle) { - context.fillStyle = fillStyle; - context.beginPath(); - context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize/2 * radiusFactor, 0, 2*Math.PI); - context.fill(); - } - function drawRect(r, c, fillStyle) { - context.fillStyle = fillStyle; - context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); - } - - function drawCloud(c, x, y){ + var xLo = (c1 + 0.3) * tileSize; + var yLo = (r1 + 0.3) * tileSize; + var xHi = (c2 + 0.45) * tileSize; + var yHi = (r2 + 0.45) * tileSize; + context.fillStyle = color; + context.fillRect(xLo + .15 * tileSize, yLo + .15 * tileSize, xHi - xLo, yHi - yLo); + } + function drawBlock(block) { + var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); + var rowcols = block.locations.map(function (location) { + return getRowcol(level, location); + }); + rowcols.forEach(function (rowcol) { + var r = rowcol.r + animationDisplacementRowcol.r; + var c = rowcol.c + animationDisplacementRowcol.c; + context.fillStyle = blockColors[block.id % blockColors.length]; + var outlineThickness = .4; + + var complement = 1 - outlineThickness; + var outlinePixels = outlineThickness * tileSize; + if (!isAlsoThisBlock(-1, -1)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(1, -1)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(-1, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(1, 1)) context.fillRect((c + complement) * tileSize, (r + complement) * tileSize, outlinePixels, outlinePixels); + if (!isAlsoThisBlock(0, -1)) context.fillRect((c) * tileSize, (r) * tileSize, tileSize, outlinePixels); + if (!isAlsoThisBlock(0, 1)) context.fillRect((c) * tileSize, (r + complement) * tileSize, tileSize, outlinePixels); + if (!isAlsoThisBlock(-1, 0)) context.fillRect((c) * tileSize, (r) * tileSize, outlinePixels, tileSize); + if (!isAlsoThisBlock(1, 0)) context.fillRect((c + complement) * tileSize, (r) * tileSize, outlinePixels, tileSize); + + function isAlsoThisBlock(dc, dr) { + for (var i = 0; i < rowcols.length; i++) { + var otherRowcol = rowcols[i]; + if (rowcol.r + dr === otherRowcol.r && rowcol.c + dc === otherRowcol.c) return true; + } + return false; + } + }); + } + function drawQuarterPie(r, c, radiusFactor, fillStyle, quadrant) { + var cx = (c + 0.5) * tileSize; + var cy = (r + 0.5) * tileSize; + context.fillStyle = fillStyle; + context.beginPath(); + context.moveTo(cx, cy); + context.arc(cx, cy, radiusFactor * tileSize / 2, quadrant * Math.PI / 2, (quadrant + 1) * Math.PI / 2); + context.fill(); + } + function drawDiamond(r, c, fillStyle) { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = fillStyle; + roundRect(context, x, y, tileSize, tileSize, 10, true, false); + } + function drawCircle(r, c, radiusFactor, fillStyle) { + context.fillStyle = fillStyle; + context.beginPath(); + context.arc((c + 0.5) * tileSize, (r + 0.5) * tileSize, tileSize / 2 * radiusFactor, 0, 2 * Math.PI); + context.fill(); + } + function drawRect(r, c, fillStyle) { + context.fillStyle = fillStyle; + context.fillRect(c * tileSize, r * tileSize, tileSize, tileSize); + } + + function drawCloud(c, x, y) { c.fillStyle = experimentalColors[0]; /*c.beginPath(); c.rect(x, y, tileSize, tileSize); c.fill(); c.closePath();*/ - + c.beginPath(); - c.moveTo(x+tileSize*0, y+tileSize*0); - - c.bezierCurveTo(x+tileSize*0, y-tileSize*.15, x+tileSize*.33, y-tileSize*.15, x+tileSize*.33, y+tileSize*0); - c.bezierCurveTo(x+tileSize*.33, y-tileSize*.15, x+tileSize*.67, y-tileSize*.15, x+tileSize*.67, y+tileSize*0); - c.bezierCurveTo(x+tileSize*.67, y-tileSize*.15, x+tileSize*1, y-tileSize*.15, x+tileSize*1, y+tileSize*0); - - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*0, x+tileSize*1.15, y+tileSize*.33, x+tileSize*1, y+tileSize*.33); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.33, x+tileSize*1.15, y+tileSize*.67, x+tileSize*1, y+tileSize*.67); - c.bezierCurveTo(x+tileSize*1.15, y+tileSize*.67, x+tileSize*1.15, y+tileSize*1, x+tileSize*1, y+tileSize*1); - - c.bezierCurveTo(x+tileSize*1, y+tileSize*1.15, x+tileSize*.67, y+tileSize*1.15, x+tileSize*.67, y+tileSize*1); - c.bezierCurveTo(x+tileSize*.67, y+tileSize*1.15, x+tileSize*.33, y+tileSize*1.15, x+tileSize*.33, y+tileSize*1); - c.bezierCurveTo(x+tileSize*.33, y+tileSize*1.15, x+tileSize*0, y+tileSize*1.15, x+tileSize*0, y+tileSize*1); - - c.bezierCurveTo(x-tileSize*.15, y+tileSize*1, x-tileSize*.15, y+tileSize*.67, x+tileSize*0, y+tileSize*.67); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*.67, x-tileSize*.15, y+tileSize*.33, x+tileSize*0, y+tileSize*.33); - c.bezierCurveTo(x-tileSize*.15, y+tileSize*.33, x-tileSize*.15, y+tileSize*0, x+tileSize*0, y+tileSize*0); - + c.moveTo(x + tileSize * 0, y + tileSize * 0); + + c.bezierCurveTo(x + tileSize * 0, y - tileSize * .15, x + tileSize * .33, y - tileSize * .15, x + tileSize * .33, y + tileSize * 0); + c.bezierCurveTo(x + tileSize * .33, y - tileSize * .15, x + tileSize * .67, y - tileSize * .15, x + tileSize * .67, y + tileSize * 0); + c.bezierCurveTo(x + tileSize * .67, y - tileSize * .15, x + tileSize * 1, y - tileSize * .15, x + tileSize * 1, y + tileSize * 0); + + c.bezierCurveTo(x + tileSize * 1.15, y + tileSize * 0, x + tileSize * 1.15, y + tileSize * .33, x + tileSize * 1, y + tileSize * .33); + c.bezierCurveTo(x + tileSize * 1.15, y + tileSize * .33, x + tileSize * 1.15, y + tileSize * .67, x + tileSize * 1, y + tileSize * .67); + c.bezierCurveTo(x + tileSize * 1.15, y + tileSize * .67, x + tileSize * 1.15, y + tileSize * 1, x + tileSize * 1, y + tileSize * 1); + + c.bezierCurveTo(x + tileSize * 1, y + tileSize * 1.15, x + tileSize * .67, y + tileSize * 1.15, x + tileSize * .67, y + tileSize * 1); + c.bezierCurveTo(x + tileSize * .67, y + tileSize * 1.15, x + tileSize * .33, y + tileSize * 1.15, x + tileSize * .33, y + tileSize * 1); + c.bezierCurveTo(x + tileSize * .33, y + tileSize * 1.15, x + tileSize * 0, y + tileSize * 1.15, x + tileSize * 0, y + tileSize * 1); + + c.bezierCurveTo(x - tileSize * .15, y + tileSize * 1, x - tileSize * .15, y + tileSize * .67, x + tileSize * 0, y + tileSize * .67); + c.bezierCurveTo(x - tileSize * .15, y + tileSize * .67, x - tileSize * .15, y + tileSize * .33, x + tileSize * 0, y + tileSize * .33); + c.bezierCurveTo(x - tileSize * .15, y + tileSize * .33, x - tileSize * .15, y + tileSize * 0, x + tileSize * 0, y + tileSize * 0); + c.closePath(); c.fill(); //c.stroke(); } -function drawFace(snake, headCol, headRow, orientation){ - var x = headCol * tileSize; - var y = headRow * tileSize; - - var scaleFactor = 1.5; - var scale1; - var scale2; - var eye1 = tileSize*.8; - var eye2 = tileSize*.4; - - var eyeSize = tileSize/5; - var eyeRotation = 2; - var z1, z2, z3, z4, z5, z6, z7, z8; - var a1, a2, a3, a4, a5, a6, a7, a8; - var beakRotation = 1.5; - var arcDirection = false; - - switch(orientation){ - case 0: //red up and blue left - z1 = eye2; - z2 = tileSize-eye1; - z3 = eye2; - z4 = tileSize-eye2; - z5 = eye2; - z6 = tileSize-eye1; - z7 = eye2; - z8 = tileSize-eye2 - eyeRotation = 1.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize*.7; - a2 = tileSize-tileSize*.7; - a3 = tileSize*.7; - a4 = -tileSize*.3; - a5 = tileSize*.7; - a6 = tileSize*.3; - a7 = tileSize/6; - a8 = 0; - beakRotation = 1; - arcDirection = false; - break; - case 1: //red right and blue up - z1 = eye1; - z2 = eye2; - z3 = eye2; - z4 = eye2; - z5 = eye1; - z6 = eye2; - z7 = eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize*1.3; - a4 = tileSize*.7; - a5 = tileSize*.7; - a6 = tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = false; - break; - case 2: //red down and blue right - z1 = tileSize-eye2; - z2 = eye1; - z3 = tileSize-eye2; - z4 = eye2; - z5 = tileSize-eye2; - z6 = eye1; - z7 = tileSize-eye2; - z8 = eye2; - eyeRotation = 2.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize-tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize-tileSize*.7; - a4 = tileSize*1.3; - a5 = tileSize-tileSize*.7; - a6 = tileSize*.7; - a7 = tileSize/6; - a8 = 0; - beakRotation = 1; - arcDirection = true; - break; - case 3: //red left and blue down - z1 = tileSize-eye1; - z2 = tileSize-eye2; - z3 = tileSize-eye2; - z4 = tileSize-eye2; - z5 = tileSize-eye1; - z6 = tileSize-eye2; - z7 = tileSize-eye2; - z8 = tileSize-eye2; - eyeRotation = 3; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize-tileSize*.7; - a2 = tileSize-tileSize*.7; - a3 = tileSize-tileSize*1.3; - a4 = tileSize-tileSize*.7; - a5 = tileSize-tileSize*.7; - a6 = tileSize-tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = true; - break; - case 4: //green up and yellow right - z1 = tileSize-eye2; - z2 = tileSize-eye1; - z3 = tileSize-eye2; - z4 = tileSize-eye2; - z5 = tileSize-eye2; - z6 = tileSize-eye1; - z7 = tileSize-eye2; - z8 = tileSize-eye2 - eyeRotation = 2.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize-tileSize*.7; - a2 = tileSize-tileSize*.7; - a3 = tileSize-tileSize*.7; - a4 = -tileSize*.3; - a5 = tileSize-tileSize*.7; - a6 = tileSize*.3; - a7 = tileSize/6; - a8 = 0; - beakRotation = 1; - arcDirection = false; - break; - case 5: //green right and yellow down - z1 = eye1; - z2 = tileSize-eye2; - z3 = eye2; - z4 = tileSize-eye2; - z5 = eye1; - z6 = tileSize-eye2; - z7 = eye2; - z8 = tileSize-eye2; - eyeRotation = 3; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize*.7; - a2 = tileSize-tileSize*.7; - a3 = tileSize*1.3; - a4 = tileSize-tileSize*.7; - a5 = tileSize*.7; - a6 = tileSize-tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = false; - break; - case 6: //green down and yellow left - z1 = eye2; - z2 = eye1; - z3 = eye2; - z4 = eye2; - z5 = eye2; - z6 = eye1; - z7 = eye2; - z8 = eye2; - eyeRotation = 1.5; - scale1 = scaleFactor; - scale2 = 1; - - a1 = tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize*.7; - a4 = tileSize*1.3; - a5 = tileSize*.7; - a6 = tileSize*.7; - a7 = tileSize/6; - a8 = 0; - beakRotation = 1; - arcDirection = true; - break; - case 7: //green left and yellow up - z1 = tileSize-eye1; - z2 = eye2; - z3 = tileSize-eye2; - z4 = eye2; - z5 = tileSize-eye1; - z6 = eye2; - z7 = tileSize-eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize-tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize-tileSize*1.3; - a4 = tileSize*.7; - a5 = tileSize-tileSize*.7; - a6 = tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = true; - break; - case 10: //single unit snake - z1 = eye1; - z2 = eye2; - z3 = eye2; - z4 = eye2; - z5 = eye1; - z6 = eye2; - z7 = eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - a1 = tileSize*.7; - a2 = tileSize*.7; - a3 = tileSize*1.3; - a4 = tileSize*.7; - a5 = tileSize*.7; - a6 = tileSize*.7; - a7 = 0; - a8 = tileSize/6; - beakRotation = 1.5; - arcDirection = false; - break; - } - - if (snake === activeSnakeId) { //draw eyes for active snake only - context.fillStyle = "white"; - context.save(); - context.scale(scale1,scale2); - context.beginPath(); - context.arc((x+z1)/scale1, (y+z2)/scale2, eyeSize, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); + function drawFace(snake, headCol, headRow, orientation) { + var x = headCol * tileSize; + var y = headRow * tileSize; + + var scaleFactor = 1.5; + var scale1; + var scale2; + var eye1 = tileSize * .8; + var eye2 = tileSize * .4; + + var eyeSize = tileSize / 5; + var eyeRotation = 2; + var z1, z2, z3, z4, z5, z6, z7, z8; + var a1, a2, a3, a4, a5, a6, a7, a8; + var beakRotation = 1.5; + var arcDirection = false; + + switch (orientation) { + case 0: //red up and blue left + z1 = eye2; + z2 = tileSize - eye1; + z3 = eye2; + z4 = tileSize - eye2; + z5 = eye2; + z6 = tileSize - eye1; + z7 = eye2; + z8 = tileSize - eye2 + eyeRotation = 1.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize * .7; + a2 = tileSize - tileSize * .7; + a3 = tileSize * .7; + a4 = -tileSize * .3; + a5 = tileSize * .7; + a6 = tileSize * .3; + a7 = tileSize / 6; + a8 = 0; + beakRotation = 1; + arcDirection = false; + break; + case 1: //red right and blue up + z1 = eye1; + z2 = eye2; + z3 = eye2; + z4 = eye2; + z5 = eye1; + z6 = eye2; + z7 = eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize * 1.3; + a4 = tileSize * .7; + a5 = tileSize * .7; + a6 = tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = false; + break; + case 2: //red down and blue right + z1 = tileSize - eye2; + z2 = eye1; + z3 = tileSize - eye2; + z4 = eye2; + z5 = tileSize - eye2; + z6 = eye1; + z7 = tileSize - eye2; + z8 = eye2; + eyeRotation = 2.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize - tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize - tileSize * .7; + a4 = tileSize * 1.3; + a5 = tileSize - tileSize * .7; + a6 = tileSize * .7; + a7 = tileSize / 6; + a8 = 0; + beakRotation = 1; + arcDirection = true; + break; + case 3: //red left and blue down + z1 = tileSize - eye1; + z2 = tileSize - eye2; + z3 = tileSize - eye2; + z4 = tileSize - eye2; + z5 = tileSize - eye1; + z6 = tileSize - eye2; + z7 = tileSize - eye2; + z8 = tileSize - eye2; + eyeRotation = 3; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize - tileSize * .7; + a2 = tileSize - tileSize * .7; + a3 = tileSize - tileSize * 1.3; + a4 = tileSize - tileSize * .7; + a5 = tileSize - tileSize * .7; + a6 = tileSize - tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = true; + break; + case 4: //green up and yellow right + z1 = tileSize - eye2; + z2 = tileSize - eye1; + z3 = tileSize - eye2; + z4 = tileSize - eye2; + z5 = tileSize - eye2; + z6 = tileSize - eye1; + z7 = tileSize - eye2; + z8 = tileSize - eye2 + eyeRotation = 2.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize - tileSize * .7; + a2 = tileSize - tileSize * .7; + a3 = tileSize - tileSize * .7; + a4 = -tileSize * .3; + a5 = tileSize - tileSize * .7; + a6 = tileSize * .3; + a7 = tileSize / 6; + a8 = 0; + beakRotation = 1; + arcDirection = false; + break; + case 5: //green right and yellow down + z1 = eye1; + z2 = tileSize - eye2; + z3 = eye2; + z4 = tileSize - eye2; + z5 = eye1; + z6 = tileSize - eye2; + z7 = eye2; + z8 = tileSize - eye2; + eyeRotation = 3; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize * .7; + a2 = tileSize - tileSize * .7; + a3 = tileSize * 1.3; + a4 = tileSize - tileSize * .7; + a5 = tileSize * .7; + a6 = tileSize - tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = false; + break; + case 6: //green down and yellow left + z1 = eye2; + z2 = eye1; + z3 = eye2; + z4 = eye2; + z5 = eye2; + z6 = eye1; + z7 = eye2; + z8 = eye2; + eyeRotation = 1.5; + scale1 = scaleFactor; + scale2 = 1; + + a1 = tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize * .7; + a4 = tileSize * 1.3; + a5 = tileSize * .7; + a6 = tileSize * .7; + a7 = tileSize / 6; + a8 = 0; + beakRotation = 1; + arcDirection = true; + break; + case 7: //green left and yellow up + z1 = tileSize - eye1; + z2 = eye2; + z3 = tileSize - eye2; + z4 = eye2; + z5 = tileSize - eye1; + z6 = eye2; + z7 = tileSize - eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize - tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize - tileSize * 1.3; + a4 = tileSize * .7; + a5 = tileSize - tileSize * .7; + a6 = tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = true; + break; + case 10: //single unit snake + z1 = eye1; + z2 = eye2; + z3 = eye2; + z4 = eye2; + z5 = eye1; + z6 = eye2; + z7 = eye2; + z8 = eye2; + eyeRotation = 2; + scale1 = 1; + scale2 = scaleFactor; + + a1 = tileSize * .7; + a2 = tileSize * .7; + a3 = tileSize * 1.3; + a4 = tileSize * .7; + a5 = tileSize * .7; + a6 = tileSize * .7; + a7 = 0; + a8 = tileSize / 6; + beakRotation = 1.5; + arcDirection = false; + break; + } - context.fillStyle = "white"; - context.save(); - context.scale(scale1,scale2); - context.beginPath(); - context.arc((x+z3)/scale1, (y+z4)/scale2, eyeSize, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); + if (snake === activeSnakeId) { //draw eyes for active snake only + context.fillStyle = "white"; + context.save(); + context.scale(scale1, scale2); + context.beginPath(); + context.arc((x + z1) / scale1, (y + z2) / scale2, eyeSize, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); - context.fillStyle = "black"; - context.save(); - context.scale(scale1,scale2); - context.beginPath(); - context.arc((x+z5)/scale1, (y+z6)/scale2, eyeSize/2, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); - context.closePath(); - context.restore(); - context.fill(); + context.fillStyle = "white"; + context.save(); + context.scale(scale1, scale2); + context.beginPath(); + context.arc((x + z3) / scale1, (y + z4) / scale2, eyeSize, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); - context.fillStyle = "black"; - context.save(); - context.scale(scale1,scale2); + context.fillStyle = "black"; + context.save(); + context.scale(scale1, scale2); + context.beginPath(); + context.arc((x + z5) / scale1, (y + z6) / scale2, eyeSize / 2, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + + context.fillStyle = "black"; + context.save(); + context.scale(scale1, scale2); + context.beginPath(); + context.arc((x + z7) / scale1, (y + z8) / scale2, eyeSize / 2, (eyeRotation - 1) * Math.PI, eyeRotation * Math.PI, true); + context.closePath(); + context.restore(); + context.fill(); + } + + //beak + context.fillStyle = "#F9921C"; context.beginPath(); - context.arc((x+z7)/scale1, (y+z8)/scale2, eyeSize/2, (eyeRotation-1)*Math.PI, eyeRotation*Math.PI, true); + context.arc(x + a1, y + a2, tileSize / 6, (beakRotation - 1) * Math.PI, beakRotation * Math.PI, arcDirection); + context.lineTo(x + a3, y + a4); + context.lineTo(x + a5 + a7, y + a6 + a8); context.closePath(); - context.restore(); context.fill(); } - - //beak - context.fillStyle = "#F9921C"; - context.beginPath(); - context.arc(x+a1, y+a2, tileSize/6, (beakRotation-1)*Math.PI, beakRotation*Math.PI, arcDirection); - context.lineTo(x+a3, y+a4); - context.lineTo(x+a5+a7, y+a6+a8); - context.closePath(); - context.fill(); -} - + function roundRect(ctx, x, y, width, height, radius, fill, stroke) { //Gooby - if (typeof stroke === 'undefined') { - stroke = true; - } - if (typeof radius === 'undefined') { - radius = 5; - } - if (typeof radius === 'number') { - radius = {tl: radius, tr: radius, br: radius, bl: radius}; - } else { - var defaultRadius = {tl: 0, tr: 0, br: 0, bl: 0}; - for (var side in defaultRadius) { - radius[side] = radius[side] || defaultRadius[side]; + if (typeof stroke === 'undefined') { + stroke = true; + } + if (typeof radius === 'undefined') { + radius = 5; + } + if (typeof radius === 'number') { + radius = { tl: radius, tr: radius, br: radius, bl: radius }; + } else { + var defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 }; + for (var side in defaultRadius) { + radius[side] = radius[side] || defaultRadius[side]; + } + } + ctx.beginPath(); + ctx.moveTo(x + radius.tl, y); + ctx.lineTo(x + width - radius.tr, y); + ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); + ctx.lineTo(x + width, y + height - radius.br); + ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); + ctx.lineTo(x + radius.bl, y + height); + ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl); + ctx.lineTo(x, y + radius.tl); + ctx.quadraticCurveTo(x, y, x + radius.tl, y); + ctx.closePath(); + if (fill) { + ctx.fill(); + } + if (stroke) { + ctx.stroke(); } - } - ctx.beginPath(); - ctx.moveTo(x + radius.tl, y); - ctx.lineTo(x + width - radius.tr, y); - ctx.quadraticCurveTo(x + width, y, x + width, y + radius.tr); - ctx.lineTo(x + width, y + height - radius.br); - ctx.quadraticCurveTo(x + width, y + height, x + width - radius.br, y + height); - ctx.lineTo(x + radius.bl, y + height); - ctx.quadraticCurveTo(x, y + height, x, y + height - radius.bl); - ctx.lineTo(x, y + radius.tl); - ctx.quadraticCurveTo(x, y, x + radius.tl, y); - ctx.closePath(); - if (fill) { - ctx.fill(); - } - if (stroke) { - ctx.stroke(); - } } - -function shadeColor(color, percent) { - var R = parseInt(color.substring(1,3),16); - var G = parseInt(color.substring(3,5),16); - var B = parseInt(color.substring(5,7),16); + function shadeColor(color, percent) { - R = parseInt(R * (100 + percent) / 100); - G = parseInt(G * (100 + percent) / 100); - B = parseInt(B * (100 + percent) / 100); + var R = parseInt(color.substring(1, 3), 16); + var G = parseInt(color.substring(3, 5), 16); + var B = parseInt(color.substring(5, 7), 16); - R = (R<255)?R:255; - G = (G<255)?G:255; - B = (B<255)?B:255; + R = parseInt(R * (100 + percent) / 100); + G = parseInt(G * (100 + percent) / 100); + B = parseInt(B * (100 + percent) / 100); - var RR = ((R.toString(16).length==1)?"0"+R.toString(16):R.toString(16)); - var GG = ((G.toString(16).length==1)?"0"+G.toString(16):G.toString(16)); - var BB = ((B.toString(16).length==1)?"0"+B.toString(16):B.toString(16)); + R = (R < 255) ? R : 255; + G = (G < 255) ? G : 255; + B = (B < 255) ? B : 255; - return "#"+RR+GG+BB; -} + var RR = ((R.toString(16).length == 1) ? "0" + R.toString(16) : R.toString(16)); + var GG = ((G.toString(16).length == 1) ? "0" + G.toString(16) : G.toString(16)); + var BB = ((B.toString(16).length == 1) ? "0" + B.toString(16) : B.toString(16)); + + return "#" + RR + GG + BB; + } - - function drawR(r,c,fillStyle){ //Gooby + + function drawR(r, c, fillStyle) { //Gooby context.fillStyle = fillStyle; var cornerRadius = 20; context.lineJoin = "round"; context.lineWidth = 1; - context.strokeRect(c*tileSize, r*tileSize, tileSize, tileSize); + context.strokeRect(c * tileSize, r * tileSize, tileSize, tileSize); //context.fillRect(c*tileSize, r*tileSize, tileSize, tileSize); } - function drawGrid() { - var buffer = document.createElement("canvas"); - buffer.width = canvas.width; - buffer.height = canvas.height; - var localContext = buffer.getContext("2d"); + function drawGrid() { + var buffer = document.createElement("canvas"); + buffer.width = canvas.width; + buffer.height = canvas.height; + var localContext = buffer.getContext("2d"); - localContext.strokeStyle = "#fff"; - localContext.beginPath(); - for (var r = 0; r < level.height; r++) { - localContext.moveTo(0, tileSize*r); - localContext.lineTo(tileSize*level.width, tileSize*r); - } - for (var c = 0; c < level.width; c++) { - localContext.moveTo(tileSize*c, 0); - localContext.lineTo(tileSize*c, tileSize*level.height); - } - localContext.stroke(); + localContext.strokeStyle = "#fff"; + localContext.beginPath(); + for (var r = 0; r < level.height; r++) { + localContext.moveTo(0, tileSize * r); + localContext.lineTo(tileSize * level.width, tileSize * r); + } + for (var c = 0; c < level.width; c++) { + localContext.moveTo(tileSize * c, 0); + localContext.lineTo(tileSize * c, tileSize * level.height); + } + localContext.stroke(); - context.save(); - context.globalAlpha = 0.4; - context.drawImage(buffer, 0, 0); - context.restore(); - } + context.save(); + context.globalAlpha = 0.4; + context.drawImage(buffer, 0, 0); + context.restore(); + } } function findAnimation(animationTypes, objectId) { - if (animationQueueCursor === animationQueue.length) return null; - var currentAnimation = animationQueue[animationQueueCursor]; - for (var i = 1; i < currentAnimation.length; i++) { - var animation = currentAnimation[i]; - if (animationTypes.indexOf(animation[0]) !== -1 && animation[1] === objectId) return animation; - } + if (animationQueueCursor === animationQueue.length) return null; + var currentAnimation = animationQueue[animationQueueCursor]; + for (var i = 1; i < currentAnimation.length; i++) { + var animation = currentAnimation[i]; + if (animationTypes.indexOf(animation[0]) !== -1 && animation[1] === objectId) return animation; + } } function findAnimationDisplacementRowcol(objectType, objectId) { - var dr = 0; - var dc = 0; - var animationTypes = [ - "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK - "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK - ]; - // skip the current one - for (var i = animationQueueCursor + 1; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === objectId) { - dr += animation[2]; - dc += animation[3]; - } + var dr = 0; + var dc = 0; + var animationTypes = [ + "m" + objectType, // MOVE_SNAKE | MOVE_BLOCK + "t" + objectType, // TELEPORT_SNAKE | TELEPORT_BLOCK + ]; + // skip the current one + for (var i = animationQueueCursor + 1; i < animationQueue.length; i++) { + var animations = animationQueue[i]; + for (var j = 1; j < animations.length; j++) { + var animation = animations[j]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === objectId) { + dr += animation[2]; + dc += animation[3]; + } + } + } + var movementAnimation = findAnimation(animationTypes, objectId); + if (movementAnimation != null) { + dr += movementAnimation[2] * (1 - animationProgress); + dc += movementAnimation[3] * (1 - animationProgress); } - } - var movementAnimation = findAnimation(animationTypes, objectId); - if (movementAnimation != null) { - dr += movementAnimation[2] * (1 - animationProgress); - dc += movementAnimation[3] * (1 - animationProgress); - } - return {r: -dr, c: -dc}; + return { r: -dr, c: -dc }; } function hasFutureRemoveAnimation(object) { - var animationTypes = [ - EXIT_SNAKE, - DIE_BLOCK, - ]; - for (var i = animationQueueCursor; i < animationQueue.length; i++) { - var animations = animationQueue[i]; - for (var j = 1; j < animations.length; j++) { - var animation = animations[j]; - if (animationTypes.indexOf(animation[0]) !== -1 && - animation[1] === object.id) { - return true; - } + var animationTypes = [ + EXIT_SNAKE, + DIE_BLOCK, + ]; + for (var i = animationQueueCursor; i < animationQueue.length; i++) { + var animations = animationQueue[i]; + for (var j = 1; j < animations.length; j++) { + var animation = animations[j]; + if (animationTypes.indexOf(animation[0]) !== -1 && + animation[1] === object.id) { + return true; + } + } } - } } function previewPaste(hoverR, hoverC) { - var offsetR = hoverR - clipboardOffsetRowcol.r; - var offsetC = hoverC - clipboardOffsetRowcol.c; - - var newLevel = JSON.parse(JSON.stringify(level)); - var selectedLocations = []; - var selectedObjects = []; - clipboardData.selectedLocations.forEach(function(location) { - var tileCode = clipboardData.level.map[location]; - var rowcol = getRowcol(clipboardData.level, location); - var r = rowcol.r + offsetR; - var c = rowcol.c + offsetC; - if (!isInBounds(newLevel, r, c)) return; - var newLocation = getLocation(newLevel, r, c); - newLevel.map[newLocation] = tileCode; - selectedLocations.push(newLocation); - }); - clipboardData.selectedObjects.forEach(function(object) { - var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { - var rowcol = getRowcol(clipboardData.level, object.locations[i]); - rowcol.r += offsetR; - rowcol.c += offsetC; - if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { - // this location is oob - if (object.type === SNAKE) { - // snakes must be completely in bounds - return; + var offsetR = hoverR - clipboardOffsetRowcol.r; + var offsetC = hoverC - clipboardOffsetRowcol.c; + + var newLevel = JSON.parse(JSON.stringify(level)); + var selectedLocations = []; + var selectedObjects = []; + clipboardData.selectedLocations.forEach(function (location) { + var tileCode = clipboardData.level.map[location]; + var rowcol = getRowcol(clipboardData.level, location); + var r = rowcol.r + offsetR; + var c = rowcol.c + offsetC; + if (!isInBounds(newLevel, r, c)) return; + var newLocation = getLocation(newLevel, r, c); + newLevel.map[newLocation] = tileCode; + selectedLocations.push(newLocation); + }); + clipboardData.selectedObjects.forEach(function (object) { + var newLocations = []; + for (var i = 0; i < object.locations.length; i++) { + var rowcol = getRowcol(clipboardData.level, object.locations[i]); + rowcol.r += offsetR; + rowcol.c += offsetC; + if (!isInBounds(newLevel, rowcol.r, rowcol.c)) { + // this location is oob + if (object.type === SNAKE) { + // snakes must be completely in bounds + return; + } + // just skip it + continue; + } + var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); + newLocations.push(newLocation); } - // just skip it - continue; - } - var newLocation = getLocation(newLevel, rowcol.r, rowcol.c); - newLocations.push(newLocation); - } - if (newLocations.length === 0) return; // can't have a non-present object - var newObject = JSON.parse(JSON.stringify(object)); - newObject.locations = newLocations; - selectedObjects.push(newObject); - }); - return { - level: newLevel, - selectedLocations: selectedLocations, - selectedObjects: selectedObjects, - }; + if (newLocations.length === 0) return; // can't have a non-present object + var newObject = JSON.parse(JSON.stringify(object)); + newObject.locations = newLocations; + selectedObjects.push(newObject); + }); + return { + level: newLevel, + selectedLocations: selectedLocations, + selectedObjects: selectedObjects, + }; } function getNaiveOrthogonalPath(a, b) { - // does not include a, but does include b. - var rowcolA = getRowcol(level, a); - var rowcolB = getRowcol(level, b); - var path = []; - if (rowcolA.r < rowcolB.r) { - for (var r = rowcolA.r; r < rowcolB.r; r++) { - path.push(getLocation(level, r + 1, rowcolA.c)); - } - } else { - for (var r = rowcolA.r; r > rowcolB.r; r--) { - path.push(getLocation(level, r - 1, rowcolA.c)); - } - } - if (rowcolA.c < rowcolB.c) { - for (var c = rowcolA.c; c < rowcolB.c; c++) { - path.push(getLocation(level, rowcolB.r, c + 1)); + // does not include a, but does include b. + var rowcolA = getRowcol(level, a); + var rowcolB = getRowcol(level, b); + var path = []; + if (rowcolA.r < rowcolB.r) { + for (var r = rowcolA.r; r < rowcolB.r; r++) { + path.push(getLocation(level, r + 1, rowcolA.c)); + } + } else { + for (var r = rowcolA.r; r > rowcolB.r; r--) { + path.push(getLocation(level, r - 1, rowcolA.c)); + } } - } else { - for (var c = rowcolA.c; c > rowcolB.c; c--) { - path.push(getLocation(level, rowcolB.r, c - 1)); + if (rowcolA.c < rowcolB.c) { + for (var c = rowcolA.c; c < rowcolB.c; c++) { + path.push(getLocation(level, rowcolB.r, c + 1)); + } + } else { + for (var c = rowcolA.c; c > rowcolB.c; c--) { + path.push(getLocation(level, rowcolB.r, c - 1)); + } } - } - return path; + return path; } function identityFunction(x) { - return x; + return x; } function compareId(a, b) { - return operatorCompare(a.id, b.id); + return operatorCompare(a.id, b.id); } function operatorCompare(a, b) { - return a < b ? -1 : a > b ? 1 : 0; + return a < b ? -1 : a > b ? 1 : 0; } function clamp(value, min, max) { - if (value < min) return min; - if (value > max) return max; - return value; + if (value < min) return min; + if (value > max) return max; + return value; } function copyArray(array) { - return array.map(identityFunction); + return array.map(identityFunction); } function getSetIntersection(array1, array2) { - if (array1.length * array2.length === 0) return []; - return array1.filter(function(x) { return array2.indexOf(x) !== -1; }); + if (array1.length * array2.length === 0) return []; + return array1.filter(function (x) { return array2.indexOf(x) !== -1; }); } function makeScaleCoordinatesFunction(width1, width2) { - return function(location) { - return location + (width2 - width1) * Math.floor(location / width1); - }; + return function (location) { + return location + (width2 - width1) * Math.floor(location / width1); + }; } var expectHash; -window.addEventListener("hashchange", function() { - if (location.hash === expectHash) { - // We're in the middle of saveLevel() or saveReplay(). - // Don't react to that event. - expectHash = null; - return; - } - // The user typed into the url bar or used Back/Forward browser buttons, etc. - loadFromLocationHash(); +window.addEventListener("hashchange", function () { + if (location.hash === expectHash) { + // We're in the middle of saveLevel() or saveReplay(). + // Don't react to that event. + expectHash = null; + return; + } + // The user typed into the url bar or used Back/Forward browser buttons, etc. + loadFromLocationHash(); }); function loadFromLocationHash() { - var hashSegments = location.hash.split("#"); - hashSegments.shift(); // first element is always "" - if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; - var hashPairs = hashSegments.map(function(segment) { - var equalsIndex = segment.indexOf("="); - if (equalsIndex === -1) return ["", segment]; // bad - return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; - }); - - if (hashPairs[0][0] !== "level") return false; - try { - var level = parseLevel(hashPairs[0][1]); - } catch (e) { - alert(e); - return false; - } - loadLevel(level); - if (hashPairs.length > 1) { + var hashSegments = location.hash.split("#"); + hashSegments.shift(); // first element is always "" + if (!(1 <= hashSegments.length && hashSegments.length <= 2)) return false; + var hashPairs = hashSegments.map(function (segment) { + var equalsIndex = segment.indexOf("="); + if (equalsIndex === -1) return ["", segment]; // bad + return [segment.substring(0, equalsIndex), segment.substring(equalsIndex + 1)]; + }); + + if (hashPairs[0][0] !== "level") return false; try { - if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); - parseAndLoadReplay(hashPairs[1][1]); + var level = parseLevel(hashPairs[0][1]); } catch (e) { - alert(e); - return false; + alert(e); + return false; + } + loadLevel(level); + if (hashPairs.length > 1) { + try { + if (hashPairs[1][0] !== "replay") throw new Error("unexpected hash pair: " + hashPairs[1][0]); + parseAndLoadReplay(hashPairs[1][1]); + } catch (e) { + alert(e); + return false; + } } - } - return true; + return true; } // run test suite @@ -4093,5 +4073,5 @@ testTime = new Date().getTime() - testTime; loadPersistentState(); if (!loadFromLocationHash()) { - loadLevel(parseLevel(exampleLevel)); + loadLevel(parseLevel(exampleLevel)); } From cc0700c85924486c6bddc60e8f759076bb05a270 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 19:49:55 -0500 Subject: [PATCH 321/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 41dd7121..1de18fb6 100644 --- a/index.html +++ b/index.html @@ -176,7 +176,7 @@ - There and Back Again + There and Back Again gavinksong From 6457486e967a0cec07bbb3899aaea2731cd174ed Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 22:02:33 -0500 Subject: [PATCH 322/577] Update SolutionVerification.js --- SolutionVerification.js | 61 ++++++++++------------------------------- 1 file changed, 15 insertions(+), 46 deletions(-) diff --git a/SolutionVerification.js b/SolutionVerification.js index fdc1d4dc..0d77f511 100644 --- a/SolutionVerification.js +++ b/SolutionVerification.js @@ -1446,58 +1446,26 @@ var themeName = "Spring"; //Gooby var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle, experimentalColors; var curlyOutline = false; -var bg1 = "rgba(145, 198, 254 * rgba(133, 192, 255"; -var bg2 = "rgba(254, 198, 145 * rgba(255, 192, 133"; -var bg3 = "rgba(145, 254, 198 * rgba(117, 255, 192"; -var bg4 = "rgba(7, 7, 83 * rgba(0, 0, 70"; +var bg1 = ["rgba(145, 198, 254", "rgba(133, 192, 255"]; -var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; -var snakeColors2 = ["#f00", "#0f0", "#00f", "#ff0"]; -var snakeColors3 = ["#BA145C", "#E91624", "#F75802", "#FEFE28"]; +var snakeColors1 = ["#fd0c0b", "#18d11f", "#004cff", "#fdc122"]; //must be full length to satisfy tint function var fruitColors1 = ["#ff0066", "#ff36a6", "#ff6b1f", "#ff9900", "#ff2600"]; -var fruitColors2 = ["black", "black", "black", "black", "black"]; -var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spike, support, box, bolt -var spikeColors2 = ["gray", "black", "white", "black"]; -var spikeColors3 = ["#333", "#333", "#333", "#777"]; +var spikeColors1 = ["#999", "#444", "#555", "#777"]; //spokes, supports, box, bolt -var blockColors1 = [ - ["#de5a6d", "#fa65dd", "#c367e3", "#9c62fa", "#625ff0"], - ["#853641", "#963c84", "#753d88", "#5d3a96", "#3a3990"] -]; -var blockColors2 = [ - ["#999"], - ["#999"] -]; -var blockColors3 = [ - ["#de7913", "#7d46a0", "#39868b", "#41ccc2", "#ded800"], - ["#8d4d0c", "#532f6a", "#2c686d", "#207973", "#999400"] -]; -var blockColors4 = [ - ["#150612", "#a52e8b", "#990077", "#d917af", "#4d003c"], - ["#8d4d0c", "#532f6a", "#2c686d", "#207973", "#999400"] -]; +var blockColors1 = ["#de5a6d", "#fa65dd", "#c367e3", "#9c62fa", "#625ff0"]; //must be 6-digit hex colors to satisfy tint function var fontSize = tileSize * 5; var textStyle1 = ["" + fontSize + "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose -var textStyle2 = ["" + fontSize + "px Impact", "#5702c6", "#ff0098"]; -var textStyle3 = ["" + fontSize + "px Impact", "#BA145C", "#F75802"]; -var textStyle4 = ["" + fontSize + "px Impact", "#ff0", "#f00"]; var experimentalColors1 = ["white", "#ffccff"]; -var experimentalColors2 = ["white", "#FEFE28"]; var themeCounter = 0; var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor, textStyle, experimentalColors //["sky",], ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], - ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], - ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], - ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors2, spikeColors2, "white", "white", textStyle1, experimentalColors1] ]; @@ -2086,20 +2054,19 @@ function render() { textStyle = themes[themeCounter][10]; experimentalColors = themes[themeCounter][11]; - if (background.substr(0, 1) == "#") { + if (!Array.isArray(background)) { context.fillStyle = background; context.fillRect(0, 0, canvas.width, canvas.height); } else { for (var i = 0; i < level.width; i++) { //checkerboard background for (var j = 0; j < level.height; j++) { - var bgColor1 = background.substr(0, background.indexOf('*')); - var bgColor2 = background.substr(background.indexOf('*') + 2, background.length); + var bgColor1 = background[0]; + var bgColor2 = background[1]; var shade = (j + 1) * .03 + .5; if ((i + j) % 2 == 0) context.fillStyle = bgColor1 + ", " + shade + ")"; else context.fillStyle = bgColor2 + ", " + shade + ")"; context.fillRect(i * tileSize, j * tileSize, tileSize, tileSize); - //context.fillText(i+" "+j,i*tileSize, j*tileSize); } } } @@ -2182,8 +2149,9 @@ function render() { rowcol2.r -= minR; rowcol2.c -= minC; var cornerRowcol = { r: rowcol1.r, c: rowcol2.c }; - drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); - drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, blockColors[1][object.id % blockColors[1].length]); + var connectorColor = tint(blockColors[object.id % blockColors.length], .5); + drawConnector(bufferContext, rowcol1.r, rowcol1.c, cornerRowcol.r, cornerRowcol.c, connectorColor); + drawConnector(bufferContext, rowcol2.r, rowcol2.c, cornerRowcol.r, cornerRowcol.c, connectorColor); } } var r = minR + animationDisplacementRowcol.r; @@ -3026,8 +2994,8 @@ function render() { context.closePath(); var bgColor; - if ((c + r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*') + 2, background.length); + if ((c + r) % 2 == 0) bgColor = background[0]; + else bgColor = background[1]; var r1, r2, b1, b2, g1, g2; r1 = bgColor.substr(5, bgColor.indexOf(",") - 5); g1 = bgColor.substr(bgColor.indexOf(",") + 1, bgColor.indexOf(",") - 4); @@ -3050,8 +3018,8 @@ function render() { context.closePath(); var bgColor; - if ((c + r) % 2 == 0) bgColor = background.substr(0, background.indexOf('*')); - else bgColor = background.substr(background.indexOf('*') + 2, background.length); + if ((c + r) % 2 == 0) bgColor = background[0]; + else bgColor = background[1]; var r1, r2, b1, b2, g1, g2; r1 = bgColor.substr(5, bgColor.indexOf(",") - 5); g1 = bgColor.substr(bgColor.indexOf(",") + 1, bgColor.indexOf(",") - 4); @@ -3068,6 +3036,7 @@ function render() { } } + function drawTileOutlines(r, c, isOccupied, outlineThickness, curlyOutline) { //Gooby if (surface != "rainbow") { context.fillStyle = surface; From 22517988ea261bc40ca69380b77601d6dc569928 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 22:05:41 -0500 Subject: [PATCH 323/577] Update SolutionVerification.js --- SolutionVerification.js | 48 ++++++++++++++++++++++++++++------------- 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/SolutionVerification.js b/SolutionVerification.js index 0d77f511..2a96065b 100644 --- a/SolutionVerification.js +++ b/SolutionVerification.js @@ -2399,21 +2399,40 @@ function render() { } } - function getTintedColor(color, v) { - if (color.length > 6) { color = color.substring(1, color.length) } - var rgb = parseInt(color, 16); - var r = Math.abs(((rgb >> 16) & 0xFF) + v); if (r > 255) r = r - (r - 255); - var g = Math.abs(((rgb >> 8) & 0xFF) + v); if (g > 255) g = g - (g - 255); - var b = Math.abs((rgb & 0xFF) + v); if (b > 255) b = b - (b - 255); - r = Number(r < 0 || isNaN(r)) ? 0 : ((r > 255) ? 255 : r).toString(16); - if (r.length == 1) r = '0' + r; - g = Number(g < 0 || isNaN(g)) ? 0 : ((g > 255) ? 255 : g).toString(16); - if (g.length == 1) g = '0' + g; - b = Number(b < 0 || isNaN(b)) ? 0 : ((b > 255) ? 255 : b).toString(16); - if (b.length == 1) b = '0' + b; - return "#" + r + g + b; + function tint(hex, delta) { + var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); + + var r = parseInt(result[1], 16); + var g = parseInt(result[2], 16); + var b = parseInt(result[3], 16); + + r /= 255, g /= 255, b /= 255; + var max = Math.max(r, g, b), min = Math.min(r, g, b); + var h, s, l = (max + min) / 2; + + if (max == min) { + h = s = 0; // achromatic + } else { + var d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + switch (max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + h /= 6; + } + + s = s * 100; + s = Math.round(s); + l = l * 100 * delta; + l = Math.round(l); + h = Math.round(360 * h); + + return 'hsl(' + h + ', ' + s + '%, ' + l + '%)'; } + function drawObject(object) { switch (object.type) { case SNAKE: @@ -2424,8 +2443,7 @@ function render() { var nextRowcol = null var color = snakeColors[object.id % snakeColors.length]; var colorIndex = object.id % snakeColors.length; - var altColor = getTintedColor(color, 50); - if (themeName === "Classic") altColor = color; + var altColor = tint(color, 1.2); var headRowcol; var orientation = 10; for (var i = 0; i < object.locations.length; i++) { From cbfdc04b1b4ab1462d6d32d78c00149006d59052 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 22:42:42 -0500 Subject: [PATCH 324/577] Update index.html --- index.html | 84 +++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/index.html b/index.html index 1de18fb6..4bed665b 100644 --- a/index.html +++ b/index.html @@ -31,7 +31,7 @@
    Standard Puzzles
    - V + V Level Creator Note @@ -565,7 +565,7 @@
    Experimental Puzzles
    - V + V Level Creator Note @@ -573,27 +573,27 @@ - + Under Cover XeroOl - + - + Snake Filter XeroOl - + - + Platformway to Heaven thejoshwolfe - + @@ -613,35 +613,35 @@ - + Baited Trap XeroOl - + - + Gateway to Freedom LevelWorld - + - + House on Fire Gooby - + - + Cloud 9 Gooby - + @@ -649,7 +649,7 @@ Bundók Gooby - +
    @@ -658,7 +658,7 @@
    nohatcoder Puzzles
    - V + V Level Creator Note @@ -666,7 +666,7 @@ - + Fruity Gap nohatcoder @@ -674,7 +674,7 @@ - + Bridge nohatcoder @@ -682,7 +682,7 @@ - + Abyss nohatcoder @@ -690,7 +690,7 @@ - + Tube nohatcoder @@ -698,7 +698,7 @@ - + Tunnel nohatcoder @@ -706,7 +706,7 @@ - + Transport edderiofer, nohatcoder, & Gooby @@ -719,7 +719,7 @@
    Avis Anguis Puzzles
    - Verification + V Level Creator Note @@ -727,7 +727,7 @@ - + Demo Terzalo @@ -735,7 +735,7 @@ - + Level A Connorses @@ -743,7 +743,7 @@ - + Level B Connorses @@ -751,7 +751,7 @@ - + Level 1 CHz @@ -759,7 +759,7 @@ - + Level 2 CHz @@ -767,7 +767,7 @@ - + Level 3 CHz @@ -780,7 +780,7 @@
    Gameboy Puzzles
    - V + V Level Creator Note @@ -788,7 +788,7 @@ - + Level 1 freeball1 @@ -796,7 +796,7 @@ - + Level 2 freeball1 @@ -804,7 +804,7 @@ - + Level 3 freeball1 @@ -812,7 +812,7 @@ - + Level 4 freeball1 @@ -820,7 +820,7 @@ - + Level 5 freeball1 @@ -828,7 +828,7 @@ - + Level 6 freeball1 @@ -836,7 +836,7 @@ - + Level 7 freeball1 @@ -844,7 +844,7 @@ - + Level 8 freeball1 @@ -852,7 +852,7 @@ - + Level 9 freeball1 @@ -860,7 +860,7 @@ - + Level 10 freeball1 From 3d00d52997ed377ca2430b1b543c4856ea98be40 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 23:10:45 -0500 Subject: [PATCH 325/577] Update Editor.css --- Editor.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor.css b/Editor.css index e5eea1c6..a3d1c018 100644 --- a/Editor.css +++ b/Editor.css @@ -40,7 +40,7 @@ button:focus{ } button:active{ - box-shadow: .5px .5px 1px black inset; + box-shadow: 0 0 2px black inset; color: black; } From 176603ee850a538892cddd6e171bdc36397ef7cb Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 23:13:32 -0500 Subject: [PATCH 326/577] Update Editor.css --- Editor.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor.css b/Editor.css index a3d1c018..95719b9b 100644 --- a/Editor.css +++ b/Editor.css @@ -40,7 +40,7 @@ button:focus{ } button:active{ - box-shadow: 0 0 2px black inset; + box-shadow: .8pt .8pt 1px gray inset; color: black; } From 8e8d391842eef7d300f87404d60d9895d6fac901 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 23:14:47 -0500 Subject: [PATCH 327/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index 4bed665b..683f6f02 100644 --- a/index.html +++ b/index.html @@ -25,7 +25,7 @@ Template Original Snakefall Github
    -
    Show Hidden Options
    Most checkmarks contain links to solutions, though some are not accessible without a password.
    +
    Show Hidden Options
    Most flowers contain links to solutions, though some are not accessible without a password.
    Standard Puzzles
    From e7867c429d62c9a3883549a02b76b5256160602e Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 23:18:38 -0500 Subject: [PATCH 328/577] Update Editor.css --- Editor.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor.css b/Editor.css index 95719b9b..89cd7471 100644 --- a/Editor.css +++ b/Editor.css @@ -120,7 +120,7 @@ canvas{ .hotkey{ font-size: 6pt; - color: gray; + color: rgba(0,0,0,.5); font-family: Arial; } From 27fd72d2f728ab6176504b8430b07a10cc0b2bc3 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 23:18:46 -0500 Subject: [PATCH 329/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index 67606b1d..2c588c49 100644 --- a/Framework.html +++ b/Framework.html @@ -92,7 +92,7 @@ From 211ba9995a4ea0d8be6a6db4a3aaf24d1c9fb76e Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Wed, 4 Mar 2020 23:32:01 -0500 Subject: [PATCH 330/577] Update index.html --- index.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/index.html b/index.html index 683f6f02..16938eeb 100644 --- a/index.html +++ b/index.html @@ -31,7 +31,7 @@
    Standard Puzzles
    - + @@ -565,7 +565,7 @@
    Experimental Puzzles
    - + @@ -658,7 +658,7 @@
    nohatcoder Puzzles
    - + @@ -719,7 +719,7 @@
    Avis Anguis Puzzles
    - + @@ -780,7 +780,7 @@
    Gameboy Puzzles
    - + From 9b4f827024accc030923eaad2fd963dd1e8dc965 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 5 Mar 2020 15:24:27 -0500 Subject: [PATCH 331/577] Update Main.js --- Main.js | 68 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 54 insertions(+), 14 deletions(-) diff --git a/Main.js b/Main.js index a5bd6eb7..cd5532e7 100644 --- a/Main.js +++ b/Main.js @@ -48,6 +48,9 @@ var headColMove; var checkResult = false; var cr = false; var cs = false; +var postPortalSnakeOutline = []; +var portalConflicts = []; +var portalFailure = false; var tileSize = 34; var level; @@ -1466,6 +1469,7 @@ function undo(undoStuff) { undoStuffChanged(undoStuff); } function reset(undoStuff) { + portalFailure = false; animationQueue = []; animationQueueCursor = 0; paradoxes = []; @@ -1503,6 +1507,7 @@ function redoAll(undoStuff) { } var sv = "https://jmdiamond3.github.io/Snakefall-Redesign/SolutionVerification.html" + hash; + //var sv = "http://127.0.0.1:5500/Snakefall/SolutionVerification.html" + hash; copyToClipboard(sv); } function copyToClipboard(text) { @@ -1849,6 +1854,7 @@ function showEditorChanged() { } function move(dr, dc) { + portalFailure = false; if (!isAlive()) return; animationQueue = []; animationQueueCursor = 0; @@ -1965,8 +1971,9 @@ function move(dr, dc) { if (portalActivationLocations.length === 1) { var portalAnimations = [300]; if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { + portalFailure = false; animationQueue.push(portalAnimations); - } + } else portalFailure = true; portalActivationLocations = []; } // now do falling logic @@ -2193,13 +2200,14 @@ function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations }); if (activatingPortals.length === 1) { // exactly one new portal we're touching. activate it - //drawObject(newSnake("white", object.locations)); portalActivationLocations.push(activatingPortals[0]); } }); } function activatePortal(portalLocations, portalLocation, animations, changeLog) { + postPortalSnakeOutline = []; + portalConflicts = []; var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; var portalRowcol = getRowcol(level, portalLocation); var otherPortalRowcol = getRowcol(level, otherPortalLocation); @@ -2211,16 +2219,19 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) var rowcol = getRowcol(level, object.locations[i]); var r = rowcol.r + delta.r; var c = rowcol.c + delta.c; + postPortalSnakeOutline[i] = { r: rowcol.r + delta.r, c: rowcol.c + delta.c }; + if (!isInBounds(level, r, c)) return false; // out of bounds newLocations.push(getLocation(level, r, c)); } for (var i = 0; i < newLocations.length; i++) { var location = newLocations[i]; - if (!isTileCodeAir(object, null, level.map[location], 0, 0)) return false; // blocked by tile + if (!isTileCodeAir(object, null, level.map[location], 0, 0)) portalConflicts.push(getRowcol(level, location)); // blocked by tile var otherObject = findObjectAtLocation(location); - if (otherObject != null && otherObject !== object) return false; // blocked by object + if (otherObject != null && otherObject !== object) portalConflicts.push(getRowcol(level, location)); // blocked by object } + if (portalConflicts.length > 0) return false; // zappo presto! var oldState = serializeObjectState(object); @@ -2622,6 +2633,7 @@ function render() { } } + if (portalFailure) drawSnakeOutline(postPortalSnakeOutline, portalConflicts); // banners if (countSnakes() === 0 && !cs) { context.fillStyle = textStyle[1]; @@ -2747,12 +2759,12 @@ function render() { context.save(); if (activePortalLocations.indexOf(location) !== -1) { context.fillStyle = "black"; - context.strokeStyle = "white"; - context.shadowColor = "white"; + context.strokeStyle = "purple"; + context.shadowColor = "purple"; context.shadowBlur = 5; context.lineWidth = 3; context.beginPath(); - context.arc(c * tileSize + tileSize / 2, r * tileSize + tileSize / 2, tileSize / 1.7, 0, 2 * Math.PI); + context.arc(c * tileSize + tileSize / 2, r * tileSize + tileSize / 2, tileSize / 1.9, 0, 2 * Math.PI); context.closePath(); context.fill(); context.stroke(); @@ -2997,7 +3009,6 @@ function render() { context.strokeStyle = "white"; resize = tileSize * 1.4; } - //context.fillStyle = "#ff6b45"; context.beginPath(); context.moveTo(startC, startR); context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC - resize * .25, startR - resize * .1, startC - resize * .3, startR + resize * .05); @@ -4243,12 +4254,8 @@ function render() { ctx.lineTo(x, y + radius.tl); ctx.quadraticCurveTo(x, y, x + radius.tl, y); ctx.closePath(); - if (fill) { - ctx.fill(); - } - if (stroke) { - ctx.stroke(); - } + if (fill) ctx.fill(); + if (stroke) ctx.stroke(); } function shadeColor(color, percent) { @@ -4305,6 +4312,39 @@ function render() { context.drawImage(buffer, 0, 0); context.restore(); } + + function drawSnakeOutline(outline, conflicts) { + var buffer = document.createElement("canvas"); + buffer.width = canvas.width; + buffer.height = canvas.height; + var localContext = buffer.getContext("2d"); + + localContext.setLineDash([8, 4]); + localContext.strokeStyle = "white"; + localContext.lineWidth = tileSize / 6; + for (var i = 0; i < outline.length; i++) { + roundRect(localContext, outline[i].c * tileSize, outline[i].r * tileSize, tileSize, tileSize, 5, false, true); + } + + localContext.setLineDash([]); + localContext.strokeStyle = "red"; + localContext.lineWidth = tileSize / 3; + for (var i = 0; i < conflicts.length; i++) { + var c = conflicts[i].c; + var r = conflicts[i].r; + localContext.beginPath(); + localContext.moveTo((c - .2) * tileSize, (r - .2) * tileSize); + localContext.lineTo((c + 1.2) * tileSize, (r + 1.2) * tileSize); + localContext.moveTo((c + 1.2) * tileSize, (r - .2) * tileSize); + localContext.lineTo((c - .2) * tileSize, (r + 1.2) * tileSize); + localContext.stroke(); + } + + context.save(); + context.globalAlpha = 1; + context.drawImage(buffer, 0, 0); + context.restore(); + } } function findAnimation(animationTypes, objectId) { From 1541015be6dcf11857501a623aff3b2ed84b46b7 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 5 Mar 2020 22:51:22 -0500 Subject: [PATCH 332/577] Update index.html --- index.html | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/index.html b/index.html index 16938eeb..2c9ea0f5 100644 --- a/index.html +++ b/index.html @@ -282,7 +282,7 @@ - + @@ -290,7 +290,7 @@ - + @@ -597,19 +597,19 @@ - + - + - + - + From 7c100993b72c12a8ba89f6550bc1c1fadff73ec9 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 5 Mar 2020 22:59:08 -0500 Subject: [PATCH 333/577] Update index.html --- index.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/index.html b/index.html index 2c9ea0f5..af70302e 100644 --- a/index.html +++ b/index.html @@ -104,7 +104,7 @@ - + @@ -121,7 +121,7 @@ - + @@ -185,7 +185,7 @@ - + From b614fe3913e66ad63d08e6e8011994b4a56e0ce2 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 5 Mar 2020 23:18:10 -0500 Subject: [PATCH 334/577] Update Main.js --- Main.js | 41 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/Main.js b/Main.js index cd5532e7..e5725556 100644 --- a/Main.js +++ b/Main.js @@ -51,6 +51,7 @@ var cs = false; var postPortalSnakeOutline = []; var portalConflicts = []; var portalFailure = false; +var portalOutOfBounds = false; var tileSize = 34; var level; @@ -1854,6 +1855,7 @@ function showEditorChanged() { } function move(dr, dc) { + portalOutOfBounds = false; portalFailure = false; if (!isAlive()) return; animationQueue = []; @@ -2221,9 +2223,10 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) var c = rowcol.c + delta.c; postPortalSnakeOutline[i] = { r: rowcol.r + delta.r, c: rowcol.c + delta.c }; - if (!isInBounds(level, r, c)) return false; // out of bounds + if (!isInBounds(level, r, c)) portalOutOfBounds = true; // out of bounds newLocations.push(getLocation(level, r, c)); } + if (portalOutOfBounds) return false; for (var i = 0; i < newLocations.length; i++) { var location = newLocations[i]; @@ -2634,6 +2637,18 @@ function render() { } if (portalFailure) drawSnakeOutline(postPortalSnakeOutline, portalConflicts); + if (portalOutOfBounds) { + context.fillStyle = "red"; + context.font = textStyle[0]; + context.shadowOffsetX = 5; + context.shadowOffsetY = 5; + context.shadowColor = "rgba(0,0,0,0.5)"; + context.shadowBlur = 4; + var textString = "Out of Bounds"; + var textWidth = context.measureText(textString).width; + context.fillText(textString, (canvas.width / 2) - (textWidth / 2), canvas.height / 2); + } + // banners if (countSnakes() === 0 && !cs) { context.fillStyle = textStyle[1]; @@ -4319,14 +4334,32 @@ function render() { buffer.height = canvas.height; var localContext = buffer.getContext("2d"); - localContext.setLineDash([8, 4]); localContext.strokeStyle = "white"; localContext.lineWidth = tileSize / 6; for (var i = 0; i < outline.length; i++) { - roundRect(localContext, outline[i].c * tileSize, outline[i].r * tileSize, tileSize, tileSize, 5, false, true); + var c = outline[i].c; + var r = outline[i].r; + localContext.beginPath(); + localContext.moveTo((c + .35) * tileSize, r * tileSize); + localContext.lineTo((c + .65) * tileSize, r * tileSize); + localContext.moveTo((c + .9) * tileSize, r * tileSize); + localContext.arcTo((c + 1) * tileSize, r * tileSize, (c + 1) * tileSize, (r + .1) * tileSize, tileSize / 6); + localContext.moveTo((c + 1) * tileSize, (r + .35) * tileSize); + localContext.lineTo((c + 1) * tileSize, (r + .65) * tileSize); + localContext.moveTo((c + 1) * tileSize, (r + .9) * tileSize); + localContext.arcTo((c + 1) * tileSize, (r + 1) * tileSize, (c + .9) * tileSize, (r + 1) * tileSize, tileSize / 6); + localContext.moveTo((c + .65) * tileSize, (r + 1) * tileSize); + localContext.lineTo((c + .35) * tileSize, (r + 1) * tileSize); + localContext.moveTo((c + .1) * tileSize, (r + 1) * tileSize); + localContext.arcTo(c * tileSize, (r + 1) * tileSize, c * tileSize, (r + .9) * tileSize, tileSize / 6); + localContext.moveTo(c * tileSize, (r + .65) * tileSize); + localContext.lineTo(c * tileSize, (r + .35) * tileSize); + localContext.moveTo(c * tileSize, (r + .1) * tileSize); + localContext.arcTo(c * tileSize, r * tileSize, (c + .1) * tileSize, r * tileSize, tileSize / 6); + localContext.stroke(); + //roundRect(localContext, outline[i].c * tileSize, outline[i].r * tileSize, tileSize, tileSize, 5, false, true); } - localContext.setLineDash([]); localContext.strokeStyle = "red"; localContext.lineWidth = tileSize / 3; for (var i = 0; i < conflicts.length; i++) { From ff409b168eb0babd61c93d21c835cc04245160de Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 5 Mar 2020 23:21:17 -0500 Subject: [PATCH 335/577] Update Main.js --- Main.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Main.js b/Main.js index e5725556..6aa6e415 100644 --- a/Main.js +++ b/Main.js @@ -4361,15 +4361,15 @@ function render() { } localContext.strokeStyle = "red"; - localContext.lineWidth = tileSize / 3; + localContext.lineWidth = tileSize / 2.8; for (var i = 0; i < conflicts.length; i++) { var c = conflicts[i].c; var r = conflicts[i].r; localContext.beginPath(); - localContext.moveTo((c - .2) * tileSize, (r - .2) * tileSize); - localContext.lineTo((c + 1.2) * tileSize, (r + 1.2) * tileSize); - localContext.moveTo((c + 1.2) * tileSize, (r - .2) * tileSize); - localContext.lineTo((c - .2) * tileSize, (r + 1.2) * tileSize); + localContext.moveTo((c - .12) * tileSize, (r - .12) * tileSize); + localContext.lineTo((c + 1.12) * tileSize, (r + 1.12) * tileSize); + localContext.moveTo((c + 1.12) * tileSize, (r - .12) * tileSize); + localContext.lineTo((c - .12) * tileSize, (r + 1.12) * tileSize); localContext.stroke(); } From c8c1a993bdcda45c99228c4a5bf099ee3dc29255 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Thu, 5 Mar 2020 23:49:54 -0500 Subject: [PATCH 336/577] Update Main.js --- Main.js | 44 ++++++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 20 deletions(-) diff --git a/Main.js b/Main.js index 6aa6e415..611e56c4 100644 --- a/Main.js +++ b/Main.js @@ -1972,10 +1972,18 @@ function move(dr, dc) { // do portals separate from falling logic if (portalActivationLocations.length === 1) { var portalAnimations = [300]; - if (activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog)) { + var result = activatePortal(portalLocations, portalActivationLocations[0], portalAnimations, changeLog); + if (result === "works") { portalFailure = false; + portalOutOfBounds = false; animationQueue.push(portalAnimations); - } else portalFailure = true; + } else if (result === "blocked") { + portalFailure = true; + portalOutOfBounds = false; + } else if (result === "outside") { + portalFailure = true; + portalOutOfBounds = true; + } portalActivationLocations = []; } // now do falling logic @@ -2221,12 +2229,12 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) var rowcol = getRowcol(level, object.locations[i]); var r = rowcol.r + delta.r; var c = rowcol.c + delta.c; - postPortalSnakeOutline[i] = { r: rowcol.r + delta.r, c: rowcol.c + delta.c }; - - if (!isInBounds(level, r, c)) portalOutOfBounds = true; // out of bounds - newLocations.push(getLocation(level, r, c)); + if (r >= 0 && c >= 0) { + postPortalSnakeOutline[i] = { r: r, c: c }; + newLocations.push(getLocation(level, r, c)); + } + if (!isInBounds(level, r, c)) return "outside"; // out of bounds } - if (portalOutOfBounds) return false; for (var i = 0; i < newLocations.length; i++) { var location = newLocations[i]; @@ -2234,7 +2242,7 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) var otherObject = findObjectAtLocation(location); if (otherObject != null && otherObject !== object) portalConflicts.push(getRowcol(level, location)); // blocked by object } - if (portalConflicts.length > 0) return false; + if (portalConflicts.length > 0) return "blocked"; // zappo presto! var oldState = serializeObjectState(object); @@ -2246,7 +2254,7 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) delta.r, delta.c, ]); - return true; + return "works"; } function isTileCodeAir(pusher, pushedObject, tileCode, dr, dc) { @@ -2636,17 +2644,13 @@ function render() { } } - if (portalFailure) drawSnakeOutline(postPortalSnakeOutline, portalConflicts); - if (portalOutOfBounds) { - context.fillStyle = "red"; - context.font = textStyle[0]; - context.shadowOffsetX = 5; - context.shadowOffsetY = 5; - context.shadowColor = "rgba(0,0,0,0.5)"; - context.shadowBlur = 4; - var textString = "Out of Bounds"; - var textWidth = context.measureText(textString).width; - context.fillText(textString, (canvas.width / 2) - (textWidth / 2), canvas.height / 2); + if (portalFailure) { + drawSnakeOutline(postPortalSnakeOutline, portalConflicts); //failed portal diagram + if (portalOutOfBounds) { + context.strokeStyle = "rgba(255,0,0,.5)"; + context.lineWidth = tileSize / 2; + roundRect(context, 0, 0, canvas.width, canvas.height, 0, false, true); + } } // banners From 2490c4283089358fb23fe2988ea2d2546624077d Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 10:47:08 -0500 Subject: [PATCH 337/577] Update Main.js --- Main.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Main.js b/Main.js index 611e56c4..aae6ff8b 100644 --- a/Main.js +++ b/Main.js @@ -683,8 +683,6 @@ function toggleShowEditor() { showEditorChanged(); } function toggleButtonSize() { - persistentState.bigButton = !persistentState.bigButton; - savePersistentState(); var buttons = document.getElementsByClassName("bottomButton"); if (persistentState.bigButton) { for (var i = 0; i < buttons.length; i++) @@ -694,6 +692,8 @@ function toggleButtonSize() { for (var i = 0; i < buttons.length; i++) buttons[i].classList.remove("bigButton"); } + persistentState.bigButton = !persistentState.bigButton; + savePersistentState(); render(); } function toggleGrid() { @@ -702,8 +702,6 @@ function toggleGrid() { render(); } function toggleHotkeys() { - persistentState.hideHotkeys = !persistentState.hideHotkeys; - savePersistentState(); var hotkeys = document.getElementsByClassName("hotkey"); var spacers = document.getElementsByClassName("hotkeySpacer"); for (var i = 0; i < hotkeys.length; i++) { @@ -714,6 +712,8 @@ function toggleHotkeys() { if (persistentState.hideHotkeys) spacers[i].style.display = "none"; else spacers[i].style.display = "block"; } + persistentState.hideHotkeys = !persistentState.hideHotkeys; + savePersistentState(); render(); } From 9088fa6e2290865ced00d5e604147014342382da Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 10:47:19 -0500 Subject: [PATCH 338/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index af70302e..f6145502 100644 --- a/index.html +++ b/index.html @@ -482,7 +482,7 @@ - + From 5bd8536612d939662af9b2e016ff4da7f8bb0444 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 11:09:35 -0500 Subject: [PATCH 339/577] Update Main.js --- Main.js | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/Main.js b/Main.js index aae6ff8b..84668ad5 100644 --- a/Main.js +++ b/Main.js @@ -153,6 +153,9 @@ function parseLevel(string) { level.map.push(tileCode); } + var url = window.location.href; + + // objects skipWhitespace(); while (cursor < string.length) { @@ -683,6 +686,8 @@ function toggleShowEditor() { showEditorChanged(); } function toggleButtonSize() { + persistentState.bigButton = !persistentState.bigButton; + savePersistentState(); var buttons = document.getElementsByClassName("bottomButton"); if (persistentState.bigButton) { for (var i = 0; i < buttons.length; i++) @@ -692,8 +697,6 @@ function toggleButtonSize() { for (var i = 0; i < buttons.length; i++) buttons[i].classList.remove("bigButton"); } - persistentState.bigButton = !persistentState.bigButton; - savePersistentState(); render(); } function toggleGrid() { @@ -704,6 +707,7 @@ function toggleGrid() { function toggleHotkeys() { var hotkeys = document.getElementsByClassName("hotkey"); var spacers = document.getElementsByClassName("hotkeySpacer"); + var spacers2 = document.getElementsByClassName("hotkeySpacer2"); for (var i = 0; i < hotkeys.length; i++) { if (persistentState.hideHotkeys) hotkeys[i].style.display = "block"; else hotkeys[i].style.display = "none"; @@ -712,6 +716,10 @@ function toggleHotkeys() { if (persistentState.hideHotkeys) spacers[i].style.display = "none"; else spacers[i].style.display = "block"; } + for (var i = 0; i < spacers2.length; i++) { + if (persistentState.hideHotkeys) spacers2[i].style.display = "block"; + else spacers2[i].style.display = "none"; + } persistentState.hideHotkeys = !persistentState.hideHotkeys; savePersistentState(); render(); @@ -1764,9 +1772,9 @@ function haveCheatcodesBeenUsed() { var persistentState = { showEditor: false, - bigButton: false, showGrid: false, - hideHotkeys: true, + bigButton: false, + hideHotkeys: false, }; function savePersistentState() { localStorage.snakefall = JSON.stringify(persistentState); @@ -2522,7 +2530,7 @@ function render() { // throw this in there somewhere document.getElementById("showGridButton").textContent = (persistentState.showGrid ? "Hide" : "Show") + " Grid"; - document.getElementById("hideHotkeyButton").textContent = (persistentState.hideHotkeys ? "Hide" : "Show") + " Hotkeys"; + document.getElementById("hideHotkeyButton").textContent = (persistentState.hideHotkeys ? "Show" : "Hide") + " Hotkeys"; document.getElementById("bigButtonButton").textContent = (persistentState.bigButton ? "Regular" : "Large") + " Buttons"; if (animationProgress < 1.0) requestAnimationFrame(render); From c9e87140c51b5a3aee7c64eab7338b5235d1f849 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 11:10:08 -0500 Subject: [PATCH 340/577] Update Framework.html --- Framework.html | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Framework.html b/Framework.html index 2c588c49..e1953964 100644 --- a/Framework.html +++ b/Framework.html @@ -54,6 +54,7 @@ + + + - + + - + + + + +
    One Way Platforms

    O
    -

    SHIFT  O
    +

    Shift  O
    VVerify Level Creator Note
    VVerify Level Creator Note
    VVerify Level Creator Note
    VVerify Level Creator Note
    VVerify Level Creator Note Level 1DoctorEnduguDoctorEndugu
    Level 2DoctorEnduguDoctorEndugu
    Under Cover 2 XeroOl
    Low Clearance XeroOl
    Box BridgeBox Bridge XeroOl The Ordealthejoshwolfethejoshwolfe
    You Don't Have To Wait For Animationsthejoshwolfethejoshwolfe
    Fruit TempleXeroI0XeroI0 I'm sorry
    ---------------------------
    Static

    W

    S
    @@ -63,6 +64,7 @@
    Kinetic

    Shift  S

    F
    @@ -75,6 +77,7 @@
    ---------------------------
    Kinetic

    Shift  F

    C
    @@ -82,14 +85,16 @@
    Multi-Way Platforms
    Multi-Way Platforms

    M

    Shift  M

    One Way Platforms
    One Way Platforms

    O

    Shift  O
    @@ -97,6 +102,7 @@
    Turnstiles

    T

    Shift  T
    @@ -104,6 +110,7 @@
    Scissor Lifts

    X

    Shift  X
    @@ -111,6 +118,7 @@
    Liquids

    L

    Shift  L
    @@ -122,6 +130,7 @@
    +
    CONTROLS
    hover for hotkeys
    @@ -147,9 +156,8 @@

    +
    - -
    From 8f14297138b453d83407cc3e79e17b7dcac62b2c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 11:10:14 -0500 Subject: [PATCH 341/577] Update Editor.css --- Editor.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Editor.css b/Editor.css index 89cd7471..5878fca6 100644 --- a/Editor.css +++ b/Editor.css @@ -172,6 +172,13 @@ canvas{ padding: 10px; } +#bigButtonButton{ + position: absolute; + left: 10; + font-size: 20pt; + padding: 10px; +} + #bottomBlock{ text-align: center; vertical-align: top; From 39552659ec0bba13c1eff009c2d96b1cdb3fa993 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 11:14:59 -0500 Subject: [PATCH 342/577] Update Main.js --- Main.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Main.js b/Main.js index 84668ad5..d883de0c 100644 --- a/Main.js +++ b/Main.js @@ -705,23 +705,23 @@ function toggleGrid() { render(); } function toggleHotkeys() { + persistentState.hideHotkeys = !persistentState.hideHotkeys; + savePersistentState(); var hotkeys = document.getElementsByClassName("hotkey"); var spacers = document.getElementsByClassName("hotkeySpacer"); var spacers2 = document.getElementsByClassName("hotkeySpacer2"); for (var i = 0; i < hotkeys.length; i++) { - if (persistentState.hideHotkeys) hotkeys[i].style.display = "block"; - else hotkeys[i].style.display = "none"; + if (persistentState.hideHotkeys) hotkeys[i].style.display = "none"; + else hotkeys[i].style.display = "block"; } for (var i = 0; i < spacers.length; i++) { - if (persistentState.hideHotkeys) spacers[i].style.display = "none"; - else spacers[i].style.display = "block"; + if (persistentState.hideHotkeys) spacers[i].style.display = "block"; + else spacers[i].style.display = "none"; } for (var i = 0; i < spacers2.length; i++) { - if (persistentState.hideHotkeys) spacers2[i].style.display = "block"; - else spacers2[i].style.display = "none"; + if (persistentState.hideHotkeys) spacers2[i].style.display = "none"; + else spacers2[i].style.display = "block"; } - persistentState.hideHotkeys = !persistentState.hideHotkeys; - savePersistentState(); render(); } From 8c60c59140fed09a1c32fc4774d04b30ea783230 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 11:33:04 -0500 Subject: [PATCH 343/577] Update Editor.css --- Editor.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor.css b/Editor.css index 5878fca6..6b2d953f 100644 --- a/Editor.css +++ b/Editor.css @@ -39,7 +39,7 @@ button:focus{ color: white; } -button:active{ +button:active:enabled{ box-shadow: .8pt .8pt 1px gray inset; color: black; } From 3ca86390ceefb709672b04c1aecc0c3ced5d124c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 11:33:12 -0500 Subject: [PATCH 344/577] Update Main.js --- Main.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Main.js b/Main.js index d883de0c..369630f0 100644 --- a/Main.js +++ b/Main.js @@ -566,7 +566,7 @@ document.addEventListener("keydown", function (event) { case "V".charCodeAt(0): if (persistentState.showEditor && modifierMask === CTRL) { setPaintBrushTileCode("paste"); break; } case "H".charCodeAt(0): - if (modifierMask === 0) { toggleHotkeys(); break; } + if (persistentState.showEditor && modifierMask === 0) { toggleHotkeys(); break; } case "T".charCodeAt(0): if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(TURNSTILEL); break; } if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(TURNSTILER); break; } @@ -1859,6 +1859,9 @@ function showEditorChanged() { }); document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : " or WASD"; + if (!persistentState.showEditor) document.getElementById("hideHotkeyButton").disabled = true; + else document.getElementById("hideHotkeyButton").disabled = false; + render(); } From 715d2c81b5b8b173620e5d6df73e8e12f180df9f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 12:05:13 -0500 Subject: [PATCH 345/577] Update Main.js --- Main.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/Main.js b/Main.js index 369630f0..cc55d072 100644 --- a/Main.js +++ b/Main.js @@ -1470,6 +1470,9 @@ function reduceChangeLog(changeLog) { } } function undo(undoStuff) { + postPortalSnakeOutline = []; + portalConflicts = []; + portalOutOfBounds = false; if (undoStuff.undoStack.length === 0) return; // already at the beginning animationQueue = []; animationQueueCursor = 0; @@ -3073,19 +3076,17 @@ function render() { function newPlatform(r, c, isOccupied) { - var x1 = .05; - var x2 = .05; - if (isOccupied(-1, 0)) x1 = 0; - if (isOccupied(1, 0)) x2 = 0; + var x1 = (isOccupied(-1, 0)) ? 0 : .05; + var x2 = (isOccupied(1, 0)) ? 0 : .05; var platformColors = ["#ffcccc", "#ffe0cc", "#ffffcc", "#e6ffe6", "#e6e6ff"]; - for (var i = 0; i < 5; i++) { - var j = i - 1; - if (j < 0) j = 0; + for (var i = 0; i < 3; i++) { + var j = (i != 0) ? i - 1 : 0; context.beginPath(); context.moveTo(c * tileSize + tileSize * (i * x1), r * tileSize + tileSize * (.05 + (.1 * i) - (j * .02))); context.strokeStyle = platformColors[i]; - context.lineWidth = tileSize * (.1 - (i * .02)); + var lw = tileSize * (.1 - (i * .02)); + context.lineWidth = lw; context.lineTo(c * tileSize + tileSize * (1 - (i * x2)), r * tileSize + tileSize * (.05 + (.1 * i) - (j * .02))); context.stroke(); } From 4a02be5ad55be7978be8e350d45c2ff9fdda55b9 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 12:29:31 -0500 Subject: [PATCH 346/577] Update Main.js --- Main.js | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/Main.js b/Main.js index cc55d072..5f47b1e6 100644 --- a/Main.js +++ b/Main.js @@ -3356,9 +3356,18 @@ function render() { tubColor = "white"; } + context.fillStyle = color3; + roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 0, true, false); + context.shadowBlur = 10; context.lineWidth = 3.5; - for (var i = -.1; i <= 1; i += .1) { + for (var i = .1; i <= .8; i += .1) { + var mod = Math.round((i + .1) * 10) % 3; + switch (mod) { + case 0: context.strokeStyle = color2; break; + case 1: context.strokeStyle = color3; break; + case 2: context.strokeStyle = color1; break; + } context.beginPath(); context.moveTo(c * tileSize, (r + i + .1) * tileSize); context.bezierCurveTo((c + 1 / 6) * tileSize, (r + i) * tileSize, (c + 1 / 3) * tileSize, (r + i) * tileSize, (c + 1 / 2) * tileSize, (r + i + .1) * tileSize); @@ -3366,28 +3375,22 @@ function render() { context.stroke(); context.shadowBlur = 0; context.shadowColor = "transparent"; - var mod = Math.round((i + .1) * 10) % 3; - switch (mod) { - case 0: context.strokeStyle = color2; break; - case 1: context.strokeStyle = color3; break; - case 2: context.strokeStyle = color1; break; - } } - context.fillStyle = tubColor; + context.fillStyle = color3; if (!isOccupied(-1, 0)) { - if (isOccupied(-1, -1)) roundRect(context, c * tileSize - tileSize * .1, (r + .1) * tileSize, tileSize * .2, tileSize * 1.2, 0, true, false); - else roundRect(context, c * tileSize - tileSize * .1, (r - .1) * tileSize, tileSize * .2, tileSize * 1.4, 0, true, false); + if (isOccupied(-1, -1)) roundRect(context, c * tileSize - tileSize * .1, r * tileSize, tileSize * .2, tileSize, 0, true, false); + else roundRect(context, c * tileSize - tileSize * .1, r * tileSize, tileSize * .2, tileSize, 0, true, false); } if (!isOccupied(1, 0)) { - if (isOccupied(1, -1)) roundRect(context, c * tileSize + tileSize * .9, (r + .1) * tileSize, tileSize * .2, tileSize * 1.2, 0, true, false); - else roundRect(context, c * tileSize + tileSize * .9, (r - .1) * tileSize, tileSize * .2, tileSize * 1.4, 0, true, false); + if (isOccupied(1, -1)) roundRect(context, c * tileSize + tileSize * .9, r * tileSize, tileSize * .2, tileSize, 0, true, false); + else roundRect(context, c * tileSize + tileSize * .9, r * tileSize, tileSize * .2, tileSize, 0, true, false); } if (!isOccupied(0, 1)) { - if (isOccupied(-1, 1) && !isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, (r + 1.05) * tileSize, tileSize * 1.1, tileSize * .25, 0, true, false); - else if (!isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize, (r + 1.05) * tileSize, tileSize * 1.3, tileSize * .25, 0, true, false); - else if (isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, c * tileSize - tileSize * .1, (r + 1.05) * tileSize, tileSize * 1.1, tileSize * .25, 0, true, false); - else roundRect(context, c * tileSize, (r + 1.05) * tileSize, tileSize * 1.1, tileSize * .25, 0, true, false); + if (isOccupied(-1, 1) && !isOccupied(1, 1)) roundRect(context, (c - .1) * tileSize, (r + .8) * tileSize, tileSize * 1.2, tileSize * .25, 0, true, false); + else if (!isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, (c - .1) * tileSize, (r + .8) * tileSize, tileSize * 1.2, tileSize * .25, 0, true, false); + else if (isOccupied(-1, 1) && isOccupied(1, 1)) roundRect(context, (c - .1) * tileSize, (r + .8) * tileSize, tileSize * 1.2, tileSize * .25, 0, true, false); + else roundRect(context, (c - .1) * tileSize, (r + .8) * tileSize, tileSize * 1.2, tileSize * .25, 0, true, false); } context.restore(); } From f9857bd227983ebbfba65f4ee34d3ca5040e815a Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 12:31:26 -0500 Subject: [PATCH 347/577] Update Framework.html --- Framework.html | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/Framework.html b/Framework.html index e1953964..a70b0348 100644 --- a/Framework.html +++ b/Framework.html @@ -150,15 +150,16 @@
    STANDARD LEVEL
    contains only original Snakebird elements
    + + +

    Moves: 0+0
    -

    - - -
    +
    +
    From 8a8c45fcf70f9d33c5278d3b43b7a26440298c52 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 16:38:36 -0500 Subject: [PATCH 348/577] Update Main.js --- Main.js | 177 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 165 insertions(+), 12 deletions(-) diff --git a/Main.js b/Main.js index 5f47b1e6..80c047fc 100644 --- a/Main.js +++ b/Main.js @@ -2896,6 +2896,7 @@ function render() { } function drawObject(object) { + var r, c; switch (object.type) { case SNAKE: var falling = false; @@ -3015,7 +3016,9 @@ function render() { else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); } } - drawFace(object.id, headRowcol.c, headRowcol.r, orientation); + r = headRowcol.r; + c = headRowcol.c; + drawFace(object.id, c, r, orientation, getAdjacentTiles()); break; case BLOCK: drawBlock(object); @@ -3063,6 +3066,23 @@ function render() { break; default: throw unreachable(); } + function getAdjacentTiles() { + return [ + [getTile(r - 1, c - 1), + getTile(r - 1, c + 0), + getTile(r - 1, c + 1)], + [getTile(r + 0, c - 1), + null, + getTile(r + 0, c + 1)], + [getTile(r + 1, c - 1), + getTile(r + 1, c + 0), + getTile(r + 1, c + 1)], + ]; + } + function getTile(r, c) { + if (!isInBounds(level, r, c)) return null; + return level.map[getLocation(level, r, c)]; + } } function drawPlatform(r, c, adjacentTiles) { @@ -3978,7 +3998,18 @@ function render() { //c.stroke(); } - function drawFace(snake, headCol, headRow, orientation) { + function drawFace(snake, headCol, headRow, orientation, adjacentTiles) { + drawFace2(snake, headCol, headRow, orientation, isNotSpace); + function isNotSpace(dr, dc) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode === WALL || tileCode === SPIKE || tileCode === CLOUD || tileCode === BUBBLE || tileCode === LAVA || tileCode === WATER; + } + } + function drawFace2(snake, headCol, headRow, orientation, isOccupied) { + var forwardLocation; + var forwardObject; + var straight; + var x = headCol * tileSize; var y = headRow * tileSize; @@ -3992,6 +4023,7 @@ function render() { var eyeRotation = 2; var z1, z2, z3, z4, z5, z6, z7, z8; var a1, a2, a3, a4, a5, a6, a7, a8; + var b1, b2, b3, b4, b5, b6; var beakRotation = 1.5; var arcDirection = false; @@ -4009,6 +4041,19 @@ function render() { scale1 = scaleFactor; scale2 = 1; + forwardLocation = getLocation(level, headRow - 1, headCol); + forwardObject = findObjectAtLocation(forwardLocation); + if (isOccupied(-1, 0) || forwardObject != null) { + straight = false; + b1 = tileSize * .6; + b2 = 0; + b3 = tileSize * .4; + b4 = tileSize * .1; + b5 = tileSize * .2; + b6 = tileSize * .2; + } + else straight = true; + a1 = tileSize * .7; a2 = tileSize - tileSize * .7; a3 = tileSize * .7; @@ -4033,6 +4078,19 @@ function render() { scale1 = 1; scale2 = scaleFactor; + forwardLocation = getLocation(level, headRow, headCol + 1); + forwardObject = findObjectAtLocation(forwardLocation); + if (isOccupied(0, 1) || forwardObject != null) { + straight = false; + b1 = tileSize; + b2 = tileSize * .6; + b3 = -tileSize * .1; + b4 = tileSize * .4; + b5 = -tileSize * .2; + b6 = tileSize * .2; + } + else straight = true; + a1 = tileSize * .7; a2 = tileSize * .7; a3 = tileSize * 1.3; @@ -4057,6 +4115,19 @@ function render() { scale1 = scaleFactor; scale2 = 1; + forwardLocation = getLocation(level, headRow + 1, headCol); + forwardObject = findObjectAtLocation(forwardLocation); + if (isOccupied(1, 0) || forwardObject != null) { + straight = false; + b1 = tileSize * .4; + b2 = tileSize; + b3 = -tileSize * .4; + b4 = -tileSize * .1; + b5 = -tileSize * .2; + b6 = -tileSize * .2; + } + else straight = true; + a1 = tileSize - tileSize * .7; a2 = tileSize * .7; a3 = tileSize - tileSize * .7; @@ -4065,8 +4136,8 @@ function render() { a6 = tileSize * .7; a7 = tileSize / 6; a8 = 0; - beakRotation = 1; - arcDirection = true; + beakRotation = 2; + arcDirection = false; break; case 3: //red left and blue down z1 = tileSize - eye1; @@ -4081,6 +4152,19 @@ function render() { scale1 = 1; scale2 = scaleFactor; + forwardLocation = getLocation(level, headRow, headCol - 1); + forwardObject = findObjectAtLocation(forwardLocation); + if (isOccupied(0, -1) || forwardObject != null) { + straight = false; + b1 = 0; + b2 = tileSize * .4; + b3 = tileSize * .1; + b4 = -tileSize * .4; + b5 = tileSize * .2; + b6 = -tileSize * .2; + } + else straight = true; + a1 = tileSize - tileSize * .7; a2 = tileSize - tileSize * .7; a3 = tileSize - tileSize * 1.3; @@ -4089,8 +4173,8 @@ function render() { a6 = tileSize - tileSize * .7; a7 = 0; a8 = tileSize / 6; - beakRotation = 1.5; - arcDirection = true; + beakRotation = 2.5; + arcDirection = false; break; case 4: //green up and yellow right z1 = tileSize - eye2; @@ -4105,6 +4189,19 @@ function render() { scale1 = scaleFactor; scale2 = 1; + forwardLocation = getLocation(level, headRow - 1, headCol); + forwardObject = findObjectAtLocation(forwardLocation); + if (isOccupied(-1, 0) || forwardObject != null) { + straight = false; + b1 = tileSize * .4; + b2 = 0; + b3 = -tileSize * .4; + b4 = tileSize * .1; + b5 = -tileSize * .2; + b6 = tileSize * .2; + } + else straight = true; + a1 = tileSize - tileSize * .7; a2 = tileSize - tileSize * .7; a3 = tileSize - tileSize * .7; @@ -4113,8 +4210,8 @@ function render() { a6 = tileSize * .3; a7 = tileSize / 6; a8 = 0; - beakRotation = 1; - arcDirection = false; + beakRotation = 2; + arcDirection = true; break; case 5: //green right and yellow down z1 = eye1; @@ -4129,6 +4226,19 @@ function render() { scale1 = 1; scale2 = scaleFactor; + forwardLocation = getLocation(level, headRow, headCol + 1); + forwardObject = findObjectAtLocation(forwardLocation); + if (isOccupied(0, 1) || forwardObject != null) { + straight = false; + b1 = tileSize; + b2 = tileSize * .4; + b3 = -tileSize * .1; + b4 = -tileSize * .4; + b5 = -tileSize * .2; + b6 = -tileSize * .2; + } + else straight = true; + a1 = tileSize * .7; a2 = tileSize - tileSize * .7; a3 = tileSize * 1.3; @@ -4137,8 +4247,8 @@ function render() { a6 = tileSize - tileSize * .7; a7 = 0; a8 = tileSize / 6; - beakRotation = 1.5; - arcDirection = false; + beakRotation = .5; + arcDirection = true; break; case 6: //green down and yellow left z1 = eye2; @@ -4153,6 +4263,19 @@ function render() { scale1 = scaleFactor; scale2 = 1; + forwardLocation = getLocation(level, headRow + 1, headCol); + forwardObject = findObjectAtLocation(forwardLocation); + if (isOccupied(1, 0) || forwardObject != null) { + straight = false; + b1 = tileSize * .6; + b2 = tileSize; + b3 = tileSize * .4; + b4 = -tileSize * .1; + b5 = tileSize * .2; + b6 = -tileSize * .2; + } + else straight = true; + a1 = tileSize * .7; a2 = tileSize * .7; a3 = tileSize * .7; @@ -4177,6 +4300,19 @@ function render() { scale1 = 1; scale2 = scaleFactor; + forwardLocation = getLocation(level, headRow, headCol - 1); + forwardObject = findObjectAtLocation(forwardLocation); + if (isOccupied(0, -1) || forwardObject != null) { + straight = false; + b1 = 0; + b2 = tileSize * .6; + b3 = tileSize * .1; + b4 = tileSize * .4; + b5 = tileSize * .2; + b6 = tileSize * .2; + } + else straight = true; + a1 = tileSize - tileSize * .7; a2 = tileSize * .7; a3 = tileSize - tileSize * 1.3; @@ -4201,6 +4337,19 @@ function render() { scale1 = 1; scale2 = scaleFactor; + forwardLocation = getLocation(level, headRow, headCol + 1); + forwardObject = findObjectAtLocation(forwardLocation); + if (isOccupied(0, 1) || forwardObject != null) { + straight = false; + b1 = tileSize; + b2 = tileSize * .6; + b3 = -tileSize * .1; + b4 = tileSize * .4; + b5 = -tileSize * .2; + b6 = tileSize * .2; + } + else straight = true; + a1 = tileSize * .7; a2 = tileSize * .7; a3 = tileSize * 1.3; @@ -4256,8 +4405,12 @@ function render() { context.fillStyle = "#F9921C"; context.beginPath(); context.arc(x + a1, y + a2, tileSize / 6, (beakRotation - 1) * Math.PI, beakRotation * Math.PI, arcDirection); - context.lineTo(x + a3, y + a4); - context.lineTo(x + a5 + a7, y + a6 + a8); + if (straight) context.lineTo(x + a3, y + a4); + else { + context.lineTo(x + b1, y + b2); + context.lineTo(x + b1 + b3, y + b2 + b4); + context.lineTo(x + b1 + b5, y + b2 + b6); + } context.closePath(); context.fill(); } From 33a478eccb315bfddfd4cb434a2335966aba8c6e Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 17:04:38 -0500 Subject: [PATCH 349/577] Update Main.js --- Main.js | 56 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/Main.js b/Main.js index 80c047fc..267d6847 100644 --- a/Main.js +++ b/Main.js @@ -4007,7 +4007,7 @@ function render() { } function drawFace2(snake, headCol, headRow, orientation, isOccupied) { var forwardLocation; - var forwardObject; + var forwardObject = null; var straight; var x = headCol * tileSize; @@ -4041,8 +4041,10 @@ function render() { scale1 = scaleFactor; scale2 = 1; - forwardLocation = getLocation(level, headRow - 1, headCol); - forwardObject = findObjectAtLocation(forwardLocation); + if (1 <= headRow && headRow < level.height - 1) { + forwardLocation = getLocation(level, headRow - 1, headCol); + forwardObject = findObjectAtLocation(forwardLocation); + } if (isOccupied(-1, 0) || forwardObject != null) { straight = false; b1 = tileSize * .6; @@ -4078,8 +4080,10 @@ function render() { scale1 = 1; scale2 = scaleFactor; - forwardLocation = getLocation(level, headRow, headCol + 1); - forwardObject = findObjectAtLocation(forwardLocation); + if (1 <= headCol && headCol < level.width - 1) { + forwardLocation = getLocation(level, headRow, headCol + 1); + forwardObject = findObjectAtLocation(forwardLocation); + } if (isOccupied(0, 1) || forwardObject != null) { straight = false; b1 = tileSize; @@ -4115,8 +4119,10 @@ function render() { scale1 = scaleFactor; scale2 = 1; - forwardLocation = getLocation(level, headRow + 1, headCol); - forwardObject = findObjectAtLocation(forwardLocation); + if (1 <= headRow && headRow < level.height - 1) { + forwardLocation = getLocation(level, headRow + 1, headCol); + forwardObject = findObjectAtLocation(forwardLocation); + } if (isOccupied(1, 0) || forwardObject != null) { straight = false; b1 = tileSize * .4; @@ -4152,8 +4158,10 @@ function render() { scale1 = 1; scale2 = scaleFactor; - forwardLocation = getLocation(level, headRow, headCol - 1); - forwardObject = findObjectAtLocation(forwardLocation); + if (1 <= headCol && headCol < level.width - 1) { + forwardLocation = getLocation(level, headRow, headCol - 1); + forwardObject = findObjectAtLocation(forwardLocation); + } if (isOccupied(0, -1) || forwardObject != null) { straight = false; b1 = 0; @@ -4189,8 +4197,10 @@ function render() { scale1 = scaleFactor; scale2 = 1; - forwardLocation = getLocation(level, headRow - 1, headCol); - forwardObject = findObjectAtLocation(forwardLocation); + if (1 <= headRow && headRow < level.height - 1) { + forwardLocation = getLocation(level, headRow - 1, headCol); + forwardObject = findObjectAtLocation(forwardLocation); + } if (isOccupied(-1, 0) || forwardObject != null) { straight = false; b1 = tileSize * .4; @@ -4226,8 +4236,10 @@ function render() { scale1 = 1; scale2 = scaleFactor; - forwardLocation = getLocation(level, headRow, headCol + 1); - forwardObject = findObjectAtLocation(forwardLocation); + if (1 <= headCol && headCol < level.width - 1) { + forwardLocation = getLocation(level, headRow, headCol + 1); + forwardObject = findObjectAtLocation(forwardLocation); + } if (isOccupied(0, 1) || forwardObject != null) { straight = false; b1 = tileSize; @@ -4263,8 +4275,10 @@ function render() { scale1 = scaleFactor; scale2 = 1; - forwardLocation = getLocation(level, headRow + 1, headCol); - forwardObject = findObjectAtLocation(forwardLocation); + if (1 <= headRow && headRow < level.height - 1) { + forwardLocation = getLocation(level, headRow + 1, headCol); + forwardObject = findObjectAtLocation(forwardLocation); + } if (isOccupied(1, 0) || forwardObject != null) { straight = false; b1 = tileSize * .6; @@ -4300,8 +4314,10 @@ function render() { scale1 = 1; scale2 = scaleFactor; - forwardLocation = getLocation(level, headRow, headCol - 1); - forwardObject = findObjectAtLocation(forwardLocation); + if (1 <= headCol && headCol < level.width - 1) { + forwardLocation = getLocation(level, headRow, headCol - 1); + forwardObject = findObjectAtLocation(forwardLocation); + } if (isOccupied(0, -1) || forwardObject != null) { straight = false; b1 = 0; @@ -4337,8 +4353,10 @@ function render() { scale1 = 1; scale2 = scaleFactor; - forwardLocation = getLocation(level, headRow, headCol + 1); - forwardObject = findObjectAtLocation(forwardLocation); + if (1 <= headCol && headCol < level.width - 1) { + forwardLocation = getLocation(level, headRow, headCol + 1); + forwardObject = findObjectAtLocation(forwardLocation); + } if (isOccupied(0, 1) || forwardObject != null) { straight = false; b1 = tileSize; From a588be7b1e1be9e66f3ddaa23a0a92d78dc02e8a Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 19:11:28 -0500 Subject: [PATCH 350/577] Update Main.js --- Main.js | 181 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 120 insertions(+), 61 deletions(-) diff --git a/Main.js b/Main.js index 267d6847..cacf0ba7 100644 --- a/Main.js +++ b/Main.js @@ -54,6 +54,9 @@ var portalFailure = false; var portalOutOfBounds = false; var tileSize = 34; +var borderRadiusFactor = 3.4; +var borderRadius = tileSize / borderRadiusFactor; + var level; var unmoveStuff = { undoStack: [], redoStack: [], spanId: "movesSpan", undoButtonId: "unmoveButton", redoButtonId: "removeButton" }; var uneditStuff = { undoStack: [], redoStack: [], spanId: "editsSpan", undoButtonId: "uneditButton", redoButtonId: "reeditButton" }; @@ -194,8 +197,8 @@ function parseLevel(string) { skipWhitespace(); } - if (tileCounter > 0) document.getElementById("levelType").innerHTML = "EXPERIMENTAL LEVEL
    contains experimental elements"; - else document.getElementById("levelType").innerHTML = "STANDARD LEVEL
    does not contain experimental elements"; + if (tileCounter > 0) document.getElementById("levelType").innerHTML = "Experimental Level
    contains experimental elements"; + else document.getElementById("levelType").innerHTML = "Standard Level
    does not contain experimental elements"; for (var i = 0; i < upconvertedObjects.length; i++) { level.objects.push(upconvertedObjects[i]); @@ -479,6 +482,24 @@ document.addEventListener("keydown", function (event) { if (modifierMask === 0) { undo(unmoveStuff); break; } if (modifierMask === SHIFT) { redo(unmoveStuff); break; } return; + case 48: //zero + tileSize = 34; + borderRadius = tileSize / borderRadiusFactor; + textStyle[0] = tileSize * 5; + render(); + return; + case 187: //equals and plus + tileSize += 2; + borderRadius = tileSize / borderRadiusFactor; + textStyle[0] = tileSize * 5; + render(); + return; + case 189: //minus + tileSize -= 2; + borderRadius = tileSize / borderRadiusFactor; + textStyle[0] = tileSize * 5; + render(); + return; case "Q".charCodeAt(0): if (modifierMask === 0) { undo(unmoveStuff); break; } if (modifierMask === SHIFT) { redo(unmoveStuff); break; } @@ -577,7 +598,7 @@ document.addEventListener("keydown", function (event) { if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(TRELLIS); break; } case 13: //return - if (persistentState.showEditor && modifierMask === 0) { toggleTheme(); break; } + if (modifierMask === 0) { toggleTheme(); break; } case 32: // spacebar case 9: // tab if (modifierMask === 0) { switchSnakes(1); break; } @@ -649,6 +670,27 @@ document.getElementById("arrowRight").addEventListener("click", function () { move(0, 1); return; }); +document.getElementById("minus").addEventListener("click", function () { + tileSize += 2; + borderRadius = tileSize / borderRadiusFactor; + textStyle[0] = tileSize * 5; + render(); + return; +}); +document.getElementById("plus").addEventListener("click", function () { + tileSize += 2; + borderRadius = tileSize / borderRadiusFactor; + textStyle[0] = tileSize * 5; + render(); + return; +}); +document.getElementById("levelSizeText").addEventListener("click", function () { + tileSize = 34; + borderRadius = tileSize / borderRadiusFactor; + textStyle[0] = tileSize * 5; + render(); + return; +}); document.getElementById("bigButtonButton").addEventListener("click", function () { toggleButtonSize(); }); @@ -1834,10 +1876,10 @@ var blockColors4 = ["#660050", "#990033", "#b32400", "#e6b800 ", "#008000"]; var blockColors5 = ["#ffccff", "#ffc2b3", "#ffffcc", "#ccffe6", "#ccffff"]; var fontSize = tileSize * 5; -var textStyle1 = ["" + fontSize + "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose -var textStyle2 = ["" + fontSize + "px Impact", "#400080", "#ff6600"]; -var textStyle3 = ["" + fontSize + "px Impact", "#BA145C", "#F75802"]; -var textStyle4 = ["" + fontSize + "px Impact", "#ff0", "#f00"]; +var textStyle1 = [fontSize, "px Impact", "#fdc122", "#fd0c0b"]; //font, Win, Lose +var textStyle2 = [fontSize, "px Futura", "#400080", "#ff6600"]; +var textStyle3 = [fontSize, "px Impact", "#BA145C", "#F75802"]; +var textStyle4 = [fontSize, "px Arial", "#ff0", "#f00"]; var experimentalColors1 = ["white", "#ffccff"]; var experimentalColors2 = ["white", "#FEFE28"]; @@ -2669,8 +2711,8 @@ function render() { // banners if (countSnakes() === 0 && !cs) { - context.fillStyle = textStyle[1]; - context.font = textStyle[0]; + context.fillStyle = textStyle[2]; + context.font = textStyle[0] + textStyle[1]; context.shadowOffsetX = 5; context.shadowOffsetY = 5; context.shadowColor = "rgba(0,0,0,0.5)"; @@ -2679,10 +2721,11 @@ function render() { var textWidth = context.measureText(textString).width; context.fillText(textString, (canvas.width / 2) - (textWidth / 2), canvas.height / 2); checkResult = true; + document.getElementById("checkSolutionButton").disabled = false; } if (isDead()) { context.fillStyle = textStyle[2]; - context.font = textStyle[0]; + context.font = textStyle[0] + textStyle[1]; context.shadowOffsetX = 5; context.shadowOffsetY = 5; context.shadowColor = "rgba(0,0,0,0.5)"; @@ -2695,7 +2738,7 @@ function render() { if (cs && cr) { context.fillStyle = "green"; - context.font = textStyle[0]; + context.font = textStyle[0] + textStyle[1]; context.shadowOffsetX = 5; context.shadowOffsetY = 5; context.shadowColor = "rgba(0,0,0,0.5)"; @@ -2706,7 +2749,7 @@ function render() { } else if (cs && !cr) { context.fillStyle = "red"; - context.font = textStyle[0]; + context.font = textStyle[0] + textStyle[1]; context.shadowOffsetX = 5; context.shadowOffsetY = 5; context.shadowColor = "rgba(0,0,0,0.5)"; @@ -2959,35 +3002,35 @@ function render() { //determines orientation of face if (!falling) nextRowcol = getRowcol(level, object.locations[1]); if (nextRowcol.r < rowcol.r) { //last move down - roundRect(context, cx, cy, tileSize, tileSize, { bl: 10, br: 10 }, true, false); //draw head + roundRect(context, cx, cy, tileSize, tileSize, { bl: borderRadius, br: borderRadius }, true, false); //draw head if (colorIndex === 0) orientation = 2; else if (colorIndex === 1) orientation = 6; else if (colorIndex === 2) orientation = 3; else if (colorIndex === 3) orientation = 5; } else if (nextRowcol.r > rowcol.r) { //last move up - roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); //draw head + roundRect(context, cx, cy, tileSize, tileSize, { tl: borderRadius, tr: borderRadius }, true, false); //draw head if (colorIndex === 0) orientation = 0; else if (colorIndex === 1) orientation = 4; else if (colorIndex === 2) orientation = 1; else if (colorIndex === 3) orientation = 7; } else if (nextRowcol.c < rowcol.c) { //last move right - roundRect(context, cx, cy, tileSize, tileSize, { tr: 10, br: 10 }, true, false); //draw head + roundRect(context, cx, cy, tileSize, tileSize, { tr: borderRadius, br: borderRadius }, true, false); //draw head if (colorIndex === 0) orientation = 1; else if (colorIndex === 1) orientation = 5; else if (colorIndex === 2) orientation = 2; else if (colorIndex === 3) orientation = 4; } else if (nextRowcol.c > rowcol.c) { //last move left - roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); //draw head + roundRect(context, cx, cy, tileSize, tileSize, { tl: borderRadius, bl: borderRadius }, true, false); //draw head if (colorIndex === 0) orientation = 3; else if (colorIndex === 1) orientation = 7; else if (colorIndex === 2) orientation = 0; else if (colorIndex === 3) orientation = 6; } else { - roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); //draw head + roundRect(context, cx, cy, tileSize, tileSize, borderRadius, true, false); //draw head orientation = 10; } } else { @@ -2995,25 +3038,25 @@ function render() { else context.fillStyle = altColor; if (i === object.locations.length - 1) { - if (lastRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, tr: 10 }, true, false); } - else if (lastRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10, br: 10 }, true, false); } - else if (lastRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10, br: 10 }, true, false); } - else if (lastRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10, bl: 10 }, true, false); } + if (lastRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tl: borderRadius, tr: borderRadius }, true, false); } + else if (lastRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { bl: borderRadius, br: borderRadius }, true, false); } + else if (lastRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tr: borderRadius, br: borderRadius }, true, false); } + else if (lastRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tl: borderRadius, bl: borderRadius }, true, false); } } else if (i != object.locations.length - 1 && i != object.locations.length) { - if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10 }, true, false); } - else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10 }, true, false); } - else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { br: 10 }, true, false); } - else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10 }, true, false); } + if (lastRowcol.r > rowcol.r && nextRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tr: borderRadius }, true, false); } + else if (lastRowcol.r > rowcol.r && nextRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { tl: borderRadius }, true, false); } + else if (lastRowcol.r < rowcol.r && nextRowcol.c < rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { br: borderRadius }, true, false); } + else if (lastRowcol.r < rowcol.r && nextRowcol.c > rowcol.c) { roundRect(context, cx, cy, tileSize, tileSize, { bl: borderRadius }, true, false); } - else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { bl: 10 }, true, false); } - else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tl: 10 }, true, false); } - else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { br: 10 }, true, false); } - else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tr: 10 }, true, false); } + else if (lastRowcol.c > rowcol.c && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { bl: borderRadius }, true, false); } + else if (lastRowcol.c > rowcol.c && nextRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tl: borderRadius }, true, false); } + else if (lastRowcol.c < rowcol.c && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { br: borderRadius }, true, false); } + else if (lastRowcol.c < rowcol.c && nextRowcol.r > rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, { tr: borderRadius }, true, false); } else if (lastRowcol.c < rowcol.c && nextRowcol.c > rowcol.c || lastRowcol.c > rowcol.c && nextRowcol.c < rowcol.c || lastRowcol.r < rowcol.r && nextRowcol.r > rowcol.r || lastRowcol.r > rowcol.r && nextRowcol.r < rowcol.r) { roundRect(context, cx, cy, tileSize, tileSize, 0, true, false); } } - else roundRect(context, cx, cy, tileSize, tileSize, 10, true, false); + else roundRect(context, cx, cy, tileSize, tileSize, borderRadius, true, false); } } r = headRowcol.r; @@ -4023,7 +4066,7 @@ function render() { var eyeRotation = 2; var z1, z2, z3, z4, z5, z6, z7, z8; var a1, a2, a3, a4, a5, a6, a7, a8; - var b1, b2, b3, b4, b5, b6; + var b1, b2, b3, b4, b5, b6, b7, b8, b9, b10; var beakRotation = 1.5; var arcDirection = false; @@ -4049,10 +4092,12 @@ function render() { straight = false; b1 = tileSize * .6; b2 = 0; - b3 = tileSize * .4; - b4 = tileSize * .1; - b5 = tileSize * .2; + b3 = tileSize * .7; + b4 = -tileSize * .1; + b5 = tileSize; b6 = tileSize * .2; + b7 = tileSize * .2; + b8 = tileSize * .2; } else straight = true; @@ -4088,10 +4133,12 @@ function render() { straight = false; b1 = tileSize; b2 = tileSize * .6; - b3 = -tileSize * .1; - b4 = tileSize * .4; - b5 = -tileSize * .2; - b6 = tileSize * .2; + b3 = tileSize * 1.1; + b4 = tileSize * .7; + b5 = tileSize * .8; + b6 = tileSize; + b7 = -tileSize * .2; + b8 = tileSize * .2; } else straight = true; @@ -4127,10 +4174,12 @@ function render() { straight = false; b1 = tileSize * .4; b2 = tileSize; - b3 = -tileSize * .4; - b4 = -tileSize * .1; - b5 = -tileSize * .2; - b6 = -tileSize * .2; + b3 = tileSize * .3; + b4 = tileSize * 1.1; + b5 = 0; + b6 = tileSize * .8; + b7 = -tileSize * .2; + b8 = -tileSize * .2; } else straight = true; @@ -4166,10 +4215,12 @@ function render() { straight = false; b1 = 0; b2 = tileSize * .4; - b3 = tileSize * .1; - b4 = -tileSize * .4; + b3 = -tileSize * .1; + b4 = tileSize * .3; b5 = tileSize * .2; - b6 = -tileSize * .2; + b6 = 0; + b7 = tileSize * .2; + b8 = -tileSize * .2; } else straight = true; @@ -4205,10 +4256,12 @@ function render() { straight = false; b1 = tileSize * .4; b2 = 0; - b3 = -tileSize * .4; - b4 = tileSize * .1; - b5 = -tileSize * .2; + b3 = tileSize * .3; + b4 = -tileSize * .1; + b5 = 0; b6 = tileSize * .2; + b7 = -tileSize * .2; + b8 = tileSize * .2; } else straight = true; @@ -4244,10 +4297,12 @@ function render() { straight = false; b1 = tileSize; b2 = tileSize * .4; - b3 = -tileSize * .1; - b4 = -tileSize * .4; - b5 = -tileSize * .2; - b6 = -tileSize * .2; + b3 = tileSize * 1.1; + b4 = tileSize * .3; + b5 = tileSize * .8; + b6 = 0; + b7 = -tileSize * .2; + b8 = -tileSize * .2; } else straight = true; @@ -4283,10 +4338,12 @@ function render() { straight = false; b1 = tileSize * .6; b2 = tileSize; - b3 = tileSize * .4; - b4 = -tileSize * .1; - b5 = tileSize * .2; - b6 = -tileSize * .2; + b3 = tileSize * .7; + b4 = tileSize * 1.1; + b5 = tileSize; + b6 = tileSize * .8; + b7 = tileSize * .2; + b8 = -tileSize * .2; } else straight = true; @@ -4322,10 +4379,12 @@ function render() { straight = false; b1 = 0; b2 = tileSize * .6; - b3 = tileSize * .1; - b4 = tileSize * .4; + b3 = -tileSize * .1; + b4 = tileSize * .7; b5 = tileSize * .2; - b6 = tileSize * .2; + b6 = tileSize; + b7 = tileSize * .2; + b8 = tileSize * .2; } else straight = true; @@ -4426,8 +4485,8 @@ function render() { if (straight) context.lineTo(x + a3, y + a4); else { context.lineTo(x + b1, y + b2); - context.lineTo(x + b1 + b3, y + b2 + b4); - context.lineTo(x + b1 + b5, y + b2 + b6); + context.bezierCurveTo(x + b1, y + b2, x + b3, y + b4, x + b5, y + b6); + context.lineTo(x + b1 + b7, y + b2 + b8); } context.closePath(); context.fill(); From 21d9ad843a0a6e5463d8c4838728bf0831207cbb Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 19:11:46 -0500 Subject: [PATCH 351/577] Update Editor.css --- Editor.css | 50 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/Editor.css b/Editor.css index 6b2d953f..7a925b8c 100644 --- a/Editor.css +++ b/Editor.css @@ -111,7 +111,15 @@ button:active:enabled{ font-family: Arial; font-size: 12pt; color:slateblue; - margin: 0 0 10px 0; + margin: 10px 0 10px 0; + display: inline-block; + vertical-align: top; + font-weight: 900; +} + +#levelType span{ + font-size: 6pt; + font-weight: 100; } canvas{ @@ -167,6 +175,13 @@ canvas{ margin-left: 5px; } +.plusMinus{ + min-height: 20px; + min-width: 20px; + font-size: 10pt; + display: table-cell; +} + .bigButton{ font-size: 20pt; padding: 10px; @@ -201,3 +216,36 @@ canvas{ font-size: 8pt; width: 220px; } + +#levelSize{ + width: fit-content; + display: table; + margin: 0 auto; + margin-bottom: 10px; + border-radius: 5px; + background-color: rgba(0,0,0,.03); + padding: 5px 10px 5px 10px; +} + +#levelSizeText{ + display: inline-block; + padding: 5px 10px 5px 10px; + margin: 0 10px 0 10px; +} + +#levelSizeText:hover{ + cursor: default; + border-radius: 3px; + background-color: rgba(0,0,0, .05); +} + +#levelSizeText:active{ + transform: scale(.97); +} + + + + +.optionsHeaders{ + font-weight: 900; +} From 8f7f7782eb7c506c4bf9bf93f2e569b765ad029b Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 19:11:57 -0500 Subject: [PATCH 352/577] Update Framework.html --- Framework.html | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/Framework.html b/Framework.html index a70b0348..52301935 100644 --- a/Framework.html +++ b/Framework.html @@ -132,8 +132,9 @@
    -
    CONTROLS
    hover for hotkeys
    +
    Standard Level
    contains only original Snakebird elements


    +
    Game Controls

    use the arrows or WASD keys on your keyboard to move, or use the buttons below
    @@ -149,18 +150,23 @@
    -
    STANDARD LEVEL
    contains only original Snakebird elements
    - - -

    +
    Progress Tracking

    Moves: 0+0
    -
    - - +

    + +
    +
    +
    +
    Options

    +
    Level Size
    + +
    +

    +
    From 5d97aae7527b9b263914db87ef68c52d9b669a5f Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 19:41:49 -0500 Subject: [PATCH 353/577] Update Editor.css --- Editor.css | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/Editor.css b/Editor.css index 7a925b8c..b73aeead 100644 --- a/Editor.css +++ b/Editor.css @@ -215,6 +215,8 @@ canvas{ #keyboardInstructions{ font-size: 8pt; width: 220px; + text-align: center; + display: inline-block; } #levelSize{ @@ -243,9 +245,15 @@ canvas{ transform: scale(.97); } - - - .optionsHeaders{ font-weight: 900; } + +.bottomBlockBox{ + width: 280px; + text-align:center; + font-size:10pt; + font-family:Arial; + display:inline-block; + vertical-align: top; +} From 0df4dd26e07c7f4a31d5e2390002930d9a627536 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 19:42:06 -0500 Subject: [PATCH 354/577] Update Framework.html --- Framework.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Framework.html b/Framework.html index 52301935..f5f777c3 100644 --- a/Framework.html +++ b/Framework.html @@ -133,7 +133,7 @@
    Standard Level
    contains only original Snakebird elements


    -
    +
    Game Controls

    use the arrows or WASD keys on your keyboard to move, or use the buttons below
    @@ -149,7 +149,7 @@
    -
    +
    Progress Tracking

    Moves: 0+0 @@ -159,7 +159,7 @@
    -
    +
    Options

    Level Size
    From 5fd6ae86ec15f5df91fd6a0945da78bd34739e11 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 20:02:42 -0500 Subject: [PATCH 355/577] Update Main.js --- Main.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/Main.js b/Main.js index cacf0ba7..f37c0ae4 100644 --- a/Main.js +++ b/Main.js @@ -54,6 +54,9 @@ var portalFailure = false; var portalOutOfBounds = false; var tileSize = 34; +var cachedTileSize = localStorage.getItem("cachedTileSize"); +if (localStorage.getItem("cachedTileSize") === null) tileSize = 34; +else tileSize = parseInt(cachedTileSize); var borderRadiusFactor = 3.4; var borderRadius = tileSize / borderRadiusFactor; @@ -486,18 +489,21 @@ document.addEventListener("keydown", function (event) { tileSize = 34; borderRadius = tileSize / borderRadiusFactor; textStyle[0] = tileSize * 5; + localStorage.setItem("cachedTileSize", tileSize); render(); return; case 187: //equals and plus tileSize += 2; borderRadius = tileSize / borderRadiusFactor; textStyle[0] = tileSize * 5; + localStorage.setItem("cachedTileSize", tileSize); render(); return; case 189: //minus tileSize -= 2; borderRadius = tileSize / borderRadiusFactor; textStyle[0] = tileSize * 5; + localStorage.setItem("cachedTileSize", tileSize); render(); return; case "Q".charCodeAt(0): @@ -674,6 +680,7 @@ document.getElementById("minus").addEventListener("click", function () { tileSize += 2; borderRadius = tileSize / borderRadiusFactor; textStyle[0] = tileSize * 5; + localStorage.setItem("cachedTileSize", tileSize); render(); return; }); @@ -681,6 +688,7 @@ document.getElementById("plus").addEventListener("click", function () { tileSize += 2; borderRadius = tileSize / borderRadiusFactor; textStyle[0] = tileSize * 5; + localStorage.setItem("cachedTileSize", tileSize); render(); return; }); @@ -688,6 +696,7 @@ document.getElementById("levelSizeText").addEventListener("click", function () { tileSize = 34; borderRadius = tileSize / borderRadiusFactor; textStyle[0] = tileSize * 5; + localStorage.setItem("cachedTileSize", tileSize); render(); return; }); @@ -858,9 +867,9 @@ document.getElementById("themeButton").addEventListener("click", function () { toggleTheme(); }); function toggleTheme() { - if (themeCounter < themes.length - 1) themeCounter++; - else themeCounter = 0; + (themeCounter < themes.length - 1) ? themeCounter++ : themeCounter = 0; blockSupportRenderCache = []; + localStorage.setItem("cachedTheme", themeCounter); render(); document.getElementById("themeButton").innerHTML = "Theme: " + themes[themeCounter][0] + ""; } @@ -1848,7 +1857,7 @@ function isAnyCheatcodeEnabled() { !isGravityEnabled || !isCollisionEnabled ); } -var themeName = "Spring"; + var background, surface, material, snakeColors, blockColors, spikeColors, fruitColors, textStyle, experimentalColors; var curlyOutline = false; @@ -1884,8 +1893,6 @@ var textStyle4 = [fontSize, "px Arial", "#ff0", "#f00"]; var experimentalColors1 = ["white", "#ffccff"]; var experimentalColors2 = ["white", "#FEFE28"]; -var themeCounter = 0; - var themes = [ //name, background, material, surface, curlyOutline, blockColors, spikeColors, fruitColors, stemColor, textStyle, experimentalColors //["sky",], ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], @@ -1896,6 +1903,11 @@ var themes = [ //name, background, material, surface, curlyOutline, blockColors ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors5, spikeColors2, "white", "white", textStyle1, experimentalColors1] ]; +var themeCounter = 0; +var cachedTheme = localStorage.getItem("cachedTheme"); +if (cachedTheme == null || cachedTheme == "null") themeCounter = 0; +else themeCounter = cachedTheme; + function showEditorChanged() { document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; From 01295b69b35569ab4919f3aeb732490de03ed277 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 20:07:38 -0500 Subject: [PATCH 356/577] Update Main.js --- Main.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Main.js b/Main.js index f37c0ae4..bcd8c86e 100644 --- a/Main.js +++ b/Main.js @@ -1907,7 +1907,8 @@ var themeCounter = 0; var cachedTheme = localStorage.getItem("cachedTheme"); if (cachedTheme == null || cachedTheme == "null") themeCounter = 0; else themeCounter = cachedTheme; - +var themeName = themes[themeCounter][0]; +document.getElementById("themeButton").innerHTML = "Theme: " + themeName + ""; function showEditorChanged() { document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; From 68ea96edd29b40f68cff101d28fc0bc62238d3ab Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 20:11:05 -0500 Subject: [PATCH 357/577] Update Main.js --- Main.js | 40 +--------------------------------------- 1 file changed, 1 insertion(+), 39 deletions(-) diff --git a/Main.js b/Main.js index bcd8c86e..1fa3b9f6 100644 --- a/Main.js +++ b/Main.js @@ -4126,6 +4126,7 @@ function render() { arcDirection = false; break; case 1: //red right and blue up + case 10: z1 = eye1; z2 = eye2; z3 = eye2; @@ -4412,45 +4413,6 @@ function render() { beakRotation = 1.5; arcDirection = true; break; - case 10: //single unit snake - z1 = eye1; - z2 = eye2; - z3 = eye2; - z4 = eye2; - z5 = eye1; - z6 = eye2; - z7 = eye2; - z8 = eye2; - eyeRotation = 2; - scale1 = 1; - scale2 = scaleFactor; - - if (1 <= headCol && headCol < level.width - 1) { - forwardLocation = getLocation(level, headRow, headCol + 1); - forwardObject = findObjectAtLocation(forwardLocation); - } - if (isOccupied(0, 1) || forwardObject != null) { - straight = false; - b1 = tileSize; - b2 = tileSize * .6; - b3 = -tileSize * .1; - b4 = tileSize * .4; - b5 = -tileSize * .2; - b6 = tileSize * .2; - } - else straight = true; - - a1 = tileSize * .7; - a2 = tileSize * .7; - a3 = tileSize * 1.3; - a4 = tileSize * .7; - a5 = tileSize * .7; - a6 = tileSize * .7; - a7 = 0; - a8 = tileSize / 6; - beakRotation = 1.5; - arcDirection = false; - break; } if (snake === activeSnakeId) { //draw eyes for active snake only From 631888cab25978c6505b6a04a054f30a78465773 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 20:15:06 -0500 Subject: [PATCH 358/577] Update Main.js --- Main.js | 133 ++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 80 insertions(+), 53 deletions(-) diff --git a/Main.js b/Main.js index 1fa3b9f6..e2d89bfc 100644 --- a/Main.js +++ b/Main.js @@ -3760,62 +3760,89 @@ function render() { } function drawSpikes(r, c, adjacentTiles) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = spikeColors[0]; + if (themeName = "Classic") { + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = "#333"; + context.beginPath(); + context.moveTo(x + tileSize * 0.3, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.4, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.5, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.6, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.3); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3); + context.fill(); + } + else { - context.beginPath(); - context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes - context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.45, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.55, y + tileSize * 0.3); - context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); - context.lineTo(x + tileSize * 0.75, y + tileSize * 0.3); - - context.moveTo(x + tileSize * 0.7, y + tileSize * 0.25); //right spikes - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.45); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.55); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.75); - - context.moveTo(x + tileSize * 0.75, y + tileSize * 0.7); //bottom spikes - context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.55, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.45, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.25, y + tileSize * 0.7); - - context.moveTo(x + tileSize * 0.3, y + tileSize * 0.75); //left spikes - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.55); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.45); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); - context.closePath(); + var x = c * tileSize; + var y = r * tileSize; + context.fillStyle = spikeColors[0]; - /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ - context.fill(); - drawSpikeSupports(r, c, isSpike, isWall); + context.beginPath(); + context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes + context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.45, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.55, y + tileSize * 0.3); + context.lineTo(x + tileSize * 0.65, y + tileSize * 0.0); + context.lineTo(x + tileSize * 0.75, y + tileSize * 0.3); + + context.moveTo(x + tileSize * 0.7, y + tileSize * 0.25); //right spikes + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.45); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.55); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.75); + + context.moveTo(x + tileSize * 0.75, y + tileSize * 0.7); //bottom spikes + context.lineTo(x + tileSize * 0.65, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.55, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.45, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.35, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.25, y + tileSize * 0.7); + + context.moveTo(x + tileSize * 0.3, y + tileSize * 0.75); //left spikes + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.65); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.55); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.45); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); + context.closePath(); - function isSpike(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === SPIKE; - } - function isWall(dc, dr) { - var tileCode = adjacentTiles[1 + dr][1 + dc]; - return tileCode == null || tileCode === WALL; + /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); + context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); + context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); + context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ + context.fill(); + drawSpikeSupports(r, c, isSpike, isWall); + + function isSpike(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === SPIKE; + } + function isWall(dc, dr) { + var tileCode = adjacentTiles[1 + dr][1 + dc]; + return tileCode == null || tileCode === WALL; + } } } From 9c896690081fc985a8cc4877fada3ba8d1d565d6 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 20:28:02 -0500 Subject: [PATCH 359/577] Update Main.js --- Main.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Main.js b/Main.js index e2d89bfc..57c20769 100644 --- a/Main.js +++ b/Main.js @@ -64,9 +64,13 @@ var level; var unmoveStuff = { undoStack: [], redoStack: [], spanId: "movesSpan", undoButtonId: "unmoveButton", redoButtonId: "removeButton" }; var uneditStuff = { undoStack: [], redoStack: [], spanId: "editsSpan", undoButtonId: "uneditButton", redoButtonId: "reeditButton" }; var paradoxes = []; +var enhanced = false; function loadLevel(newLevel) { level = newLevel; currentSerializedLevel = compressSerialization(stringifyLevel(newLevel)); + var string = stringifyLevel(newLevel); + var levelString = string.substring(string.indexOf("?") + 1, string.indexOf("/")); + if (levelString.match(/[a-z]/i)) enhanced = true; activateAnySnakePlease(); unmoveStuff.undoStack = []; @@ -200,8 +204,8 @@ function parseLevel(string) { skipWhitespace(); } - if (tileCounter > 0) document.getElementById("levelType").innerHTML = "Experimental Level
    contains experimental elements"; - else document.getElementById("levelType").innerHTML = "Standard Level
    does not contain experimental elements"; + if (enhanced) document.getElementById("levelType").innerHTML = "Enhanced Level
    contains new elements not present in the original Snakebird game"; + else document.getElementById("levelType").innerHTML = "Standard Level
    contains only original Snakebird elements"; for (var i = 0; i < upconvertedObjects.length; i++) { level.objects.push(upconvertedObjects[i]); From 279491c437d9555dbfa46620a172c0d0066376a4 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 20:31:16 -0500 Subject: [PATCH 360/577] Update Main.js --- Main.js | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) diff --git a/Main.js b/Main.js index 57c20769..7e2e44f7 100644 --- a/Main.js +++ b/Main.js @@ -3764,9 +3764,9 @@ function render() { } function drawSpikes(r, c, adjacentTiles) { - if (themeName = "Classic") { - var x = c * tileSize; - var y = r * tileSize; + var x = c * tileSize; + var y = r * tileSize; + if (themeName === "Classic") { context.fillStyle = "#333"; context.beginPath(); context.moveTo(x + tileSize * 0.3, y + tileSize * 0.3); @@ -3789,11 +3789,7 @@ function render() { context.fill(); } else { - - var x = c * tileSize; - var y = r * tileSize; context.fillStyle = spikeColors[0]; - context.beginPath(); context.moveTo(x + tileSize * 0.25, y + tileSize * 0.3); //top spikes context.lineTo(x + tileSize * 0.35, y + tileSize * 0.0); @@ -3823,19 +3819,6 @@ function render() { context.lineTo(x + tileSize * 0.0, y + tileSize * 0.35); context.lineTo(x + tileSize * 0.3, y + tileSize * 0.25); context.closePath(); - - /*context.lineTo(x + tileSize * 1.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.5); - context.lineTo(x + tileSize * 1.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.7, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.6, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.5, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.4, y + tileSize * 1.0); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.7); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.6); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.5); - context.lineTo(x + tileSize * 0.0, y + tileSize * 0.4); - context.lineTo(x + tileSize * 0.3, y + tileSize * 0.3);*/ context.fill(); drawSpikeSupports(r, c, isSpike, isWall); From d18063441989d642c6ec6b357e5e45565b1e7104 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 23:32:57 -0500 Subject: [PATCH 361/577] Update Main.js --- Main.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Main.js b/Main.js index 7e2e44f7..5943748b 100644 --- a/Main.js +++ b/Main.js @@ -704,6 +704,16 @@ document.getElementById("levelSizeText").addEventListener("click", function () { render(); return; }); +document.getElementById("fitButton").addEventListener("click", function () { + var maxW = screen.width / level.width; + var maxH = screen.height / level.height; + tileSize = Math.min(maxW, maxH) * .8; + borderRadius = tileSize / borderRadiusFactor; + textStyle[0] = tileSize * 5; + localStorage.setItem("cachedTileSize", tileSize); + render(); + return; +}); document.getElementById("bigButtonButton").addEventListener("click", function () { toggleButtonSize(); }); From 6f2b719b505632c6d93ce49d2d47cce75bf75490 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 23:33:02 -0500 Subject: [PATCH 362/577] Update Editor.css --- Editor.css | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Editor.css b/Editor.css index b73aeead..30503265 100644 --- a/Editor.css +++ b/Editor.css @@ -227,6 +227,7 @@ canvas{ border-radius: 5px; background-color: rgba(0,0,0,.03); padding: 5px 10px 5px 10px; + position: relative; } #levelSizeText{ @@ -257,3 +258,22 @@ canvas{ display:inline-block; vertical-align: top; } + +#fitButton{ + position: absolute; + font-size: 8pt; + top: 23%; + left: -30px; + cursor: default; + padding: 3px; + border-radius: 2px; +} + +#fitButton:hover{ + background-color: slateblue; + color: white; +} + +#fitButton:active{ + transform: scale(.9); +} From 2c579484b666f87770389480a28680edbdf51895 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 23:33:10 -0500 Subject: [PATCH 363/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index f5f777c3..79af0ca6 100644 --- a/Framework.html +++ b/Framework.html @@ -161,7 +161,7 @@
    Options

    -
    Level Size
    +
    FIT
    Level Size



    From 6568920463fe68a4703684a0f0b592f25d843584 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 23:41:55 -0500 Subject: [PATCH 364/577] Update Main.js --- Main.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/Main.js b/Main.js index 5943748b..1e0ad3f0 100644 --- a/Main.js +++ b/Main.js @@ -565,6 +565,7 @@ document.addEventListener("keydown", function (event) { case "F".charCodeAt(0): if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(POISON_FRUIT); break; } + if (!persistentState.showEditor && modifierMask === 0) { fitCanvas(); break; } return; case "D".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } @@ -705,12 +706,7 @@ document.getElementById("levelSizeText").addEventListener("click", function () { return; }); document.getElementById("fitButton").addEventListener("click", function () { - var maxW = screen.width / level.width; - var maxH = screen.height / level.height; - tileSize = Math.min(maxW, maxH) * .8; - borderRadius = tileSize / borderRadiusFactor; - textStyle[0] = tileSize * 5; - localStorage.setItem("cachedTileSize", tileSize); + fitCanvas(); render(); return; }); @@ -745,6 +741,15 @@ document.getElementById("removeButton").addEventListener("click", function () { document.getElementById("showHideEditor").addEventListener("click", function () { toggleShowEditor(); }); +function fitCanvas() { + var maxW = screen.width / level.width; + var maxH = screen.height / level.height; + tileSize = Math.min(maxW, maxH) * .8; + borderRadius = tileSize / borderRadiusFactor; + textStyle[0] = tileSize * 5; + localStorage.setItem("cachedTileSize", tileSize); + location.reload(); //without this, tiles appear to have borders +} function toggleShowEditor() { persistentState.showEditor = !persistentState.showEditor; savePersistentState(); From c35727cbded099166e8ef7971c4a133b87440fa0 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 23:42:09 -0500 Subject: [PATCH 365/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index 79af0ca6..19ff88f5 100644 --- a/Framework.html +++ b/Framework.html @@ -161,7 +161,7 @@
    Options

    -
    FIT
    Level Size
    +
    FIT
    Level Size



    From ceadc9206259bd8a46d0f6c7addb39d3b65f68a5 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 23:46:10 -0500 Subject: [PATCH 366/577] Update Editor.css --- Editor.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor.css b/Editor.css index 30503265..5cce9af0 100644 --- a/Editor.css +++ b/Editor.css @@ -262,7 +262,7 @@ canvas{ #fitButton{ position: absolute; font-size: 8pt; - top: 23%; + top: 25%; left: -30px; cursor: default; padding: 3px; From a6623197799cde9711b1bef4ddbbbb414ac7075a Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 23:51:32 -0500 Subject: [PATCH 367/577] Update Main.js --- Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.js b/Main.js index 1e0ad3f0..e4d97015 100644 --- a/Main.js +++ b/Main.js @@ -682,7 +682,7 @@ document.getElementById("arrowRight").addEventListener("click", function () { return; }); document.getElementById("minus").addEventListener("click", function () { - tileSize += 2; + tileSize -= 2; borderRadius = tileSize / borderRadiusFactor; textStyle[0] = tileSize * 5; localStorage.setItem("cachedTileSize", tileSize); From 3e5858c24641e0a9162ac12e8234ca1903f93754 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 23:51:44 -0500 Subject: [PATCH 368/577] Update Editor.css --- Editor.css | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Editor.css b/Editor.css index 5cce9af0..308d236e 100644 --- a/Editor.css +++ b/Editor.css @@ -34,6 +34,10 @@ button{ box-shadow: .5px .5px 1px black; } +button:hover:enabled{ + color: slateblue; +} + button:focus{ background-image: linear-gradient(#4b91ff, #055ce4); color: white; @@ -239,7 +243,8 @@ canvas{ #levelSizeText:hover{ cursor: default; border-radius: 3px; - background-color: rgba(0,0,0, .05); + background-color: slateblue; + color: white; } #levelSizeText:active{ @@ -265,7 +270,7 @@ canvas{ top: 25%; left: -30px; cursor: default; - padding: 3px; + padding: 3px 5px 3px 5px; border-radius: 2px; } From 946a15ee9405bbef05efb1a808d0ea0b5d5b7eef Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Fri, 6 Mar 2020 23:52:43 -0500 Subject: [PATCH 369/577] Update Main.js --- Main.js | 1 + 1 file changed, 1 insertion(+) diff --git a/Main.js b/Main.js index e4d97015..eca18cb8 100644 --- a/Main.js +++ b/Main.js @@ -566,6 +566,7 @@ document.addEventListener("keydown", function (event) { if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(POISON_FRUIT); break; } if (!persistentState.showEditor && modifierMask === 0) { fitCanvas(); break; } + if (persistentState.showEditor && modifierMask === CTRL) { fitCanvas(); break; } return; case "D".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } From a9232a86555ad39ae073bd10784946c470eb85cc Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 00:02:17 -0500 Subject: [PATCH 370/577] Update Main.js --- Main.js | 80 +++++++++++++++++++++++++++++++-------------------------- 1 file changed, 43 insertions(+), 37 deletions(-) diff --git a/Main.js b/Main.js index eca18cb8..25770bba 100644 --- a/Main.js +++ b/Main.js @@ -3102,43 +3102,7 @@ function render() { case FRUIT: case POISON_FRUIT: var is_poison = object.type == POISON_FRUIT; - rowcol = getRowcol(level, object.locations[0]); - var c = rowcol.c; - var r = rowcol.r; - var startC = c * tileSize + tileSize / 2; - var startR = r * tileSize + tileSize * .2; - var resize = tileSize * 1.7; - var color = fruitColors[object.id % fruitColors.length]; - var stemColor = themes[themeCounter][9] - if (themeName === "Classic") color = "#f0f"; - if (is_poison) { color = "#666600"; stemColor = "black"; } - context.fillStyle = color; - if (themeName != "Classic") { - if (surface == "rainbow") { - stemColor = "white"; - if (!is_poison) context.fillStyle = "black"; - context.lineWidth = tileSize / 8; - context.strokeStyle = "white"; - resize = tileSize * 1.4; - } - context.beginPath(); - context.moveTo(startC, startR); - context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC - resize * .25, startR - resize * .1, startC - resize * .3, startR + resize * .05); - context.bezierCurveTo(startC - resize * .35, startR + resize * .15, startC - resize * .3, startR + resize * .6, startC, startR + resize * .5); - context.bezierCurveTo(startC + resize * .3, startR + resize * .6, startC + resize * .35, startR + resize * .15, startC + resize * .3, startR + resize * .05); - context.bezierCurveTo(startC + resize * .25, startR - resize * .05, startC + resize * .1, startR - resize * .1, startC, startR); - context.closePath(); - context.fill(); - if (surface == "rainbow") context.stroke(); - - context.beginPath(); - context.moveTo(startC, startR); - context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC, startR - resize * .1, startC - resize * .1, startR - resize * .15); - context.bezierCurveTo(startC, startR - resize * .1, startC + resize * .05, startR - resize * .1, startC, startR); - context.fillStyle = stemColor; - context.fill(); - } - else drawCircle(rowcol.r, rowcol.c, 1, color); + drawFruit(rowcol, object, is_poison); break; default: throw unreachable(); } @@ -3978,6 +3942,47 @@ function render() { context.stroke(); } + function drawFruit(rowcol, object, is_poison) { + var is_poison = object.type == POISON_FRUIT; + rowcol = getRowcol(level, object.locations[0]); + var c = rowcol.c; + var r = rowcol.r; + var startC = c * tileSize + tileSize / 2; + var startR = r * tileSize + tileSize * .08; + var resize = tileSize * 1.7; + var color = fruitColors[object.id % fruitColors.length]; + var stemColor = themes[themeCounter][9] + if (themeName === "Classic") color = "#f0f"; + if (is_poison) { color = "#666600"; stemColor = "black"; } + context.fillStyle = color; + if (themeName != "Classic") { + if (surface == "rainbow") { + stemColor = "white"; + if (!is_poison) context.fillStyle = "black"; + context.lineWidth = tileSize / 8; + context.strokeStyle = "white"; + resize = tileSize * 1.4; + } + context.beginPath(); + context.moveTo(startC, startR); + context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC - resize * .25, startR - resize * .1, startC - resize * .3, startR + resize * .05); + context.bezierCurveTo(startC - resize * .35, startR + resize * .15, startC - resize * .3, startR + resize * .6, startC, startR + resize * .5); + context.bezierCurveTo(startC + resize * .3, startR + resize * .6, startC + resize * .35, startR + resize * .15, startC + resize * .3, startR + resize * .05); + context.bezierCurveTo(startC + resize * .25, startR - resize * .05, startC + resize * .1, startR - resize * .1, startC, startR); + context.closePath(); + context.fill(); + if (surface == "rainbow") context.stroke(); + + context.beginPath(); + context.moveTo(startC, startR); + context.bezierCurveTo(startC - resize * .1, startR - resize * .05, startC, startR - resize * .1, startC - resize * .1, startR - resize * .15); + context.bezierCurveTo(startC, startR - resize * .1, startC + resize * .05, startR - resize * .1, startC, startR); + context.fillStyle = stemColor; + context.fill(); + } + else drawCircle(r, c, 1, color); + } + function drawConnector(context, r1, c1, r2, c2, color) { // either r1 and r2 or c1 and c2 must be equal if (r1 > r2 || c1 > c2) { @@ -3996,6 +4001,7 @@ function render() { context.fillStyle = color; context.fillRect(xLo, yLo, xHi - xLo, yHi - yLo); } + function drawBlock(block) { var animationDisplacementRowcol = findAnimationDisplacementRowcol(block.type, block.id); var rowcols = block.locations.map(function (location) { From 8021dfb5239d80eaf1c88c65d6cf9f56fc84cf24 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 00:04:14 -0500 Subject: [PATCH 371/577] Update Main.js --- Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.js b/Main.js index 25770bba..4defb664 100644 --- a/Main.js +++ b/Main.js @@ -2757,7 +2757,7 @@ function render() { document.getElementById("checkSolutionButton").disabled = false; } if (isDead()) { - context.fillStyle = textStyle[2]; + context.fillStyle = textStyle[3]; context.font = textStyle[0] + textStyle[1]; context.shadowOffsetX = 5; context.shadowOffsetY = 5; From 114bcf8f1dfbed070f8811dc50bc53a9fe91059c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 00:50:39 -0500 Subject: [PATCH 372/577] Update Main.js --- Main.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Main.js b/Main.js index 4defb664..930a54b2 100644 --- a/Main.js +++ b/Main.js @@ -763,10 +763,13 @@ function toggleButtonSize() { if (persistentState.bigButton) { for (var i = 0; i < buttons.length; i++) buttons[i].classList.add("bigButton"); + document.getElementById("fitButton").style.display = "none"; + } else { for (var i = 0; i < buttons.length; i++) buttons[i].classList.remove("bigButton"); + document.getElementById("fitButton").style.display = "block"; } render(); } @@ -2694,7 +2697,12 @@ function render() { for (var i = 0; i < objects.length; i++) { var object = objects[i]; - if (object.type === SNAKE || object.type === BLOCK) drawObject(object); //draws snakes and blocks + if (object.type === SNAKE) drawObject(object); + } + + for (var i = 0; i < objects.length; i++) { + var object = objects[i]; + if (object.type === BLOCK) drawObject(object); } if (onlyTheseObjects == null) { From 9547965aca76e82c595d6cb632c0836f8b2b4c7b Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 14:30:15 -0500 Subject: [PATCH 373/577] Update Main.js --- Main.js | 113 ++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 72 insertions(+), 41 deletions(-) diff --git a/Main.js b/Main.js index 930a54b2..5d997a9f 100644 --- a/Main.js +++ b/Main.js @@ -52,6 +52,8 @@ var postPortalSnakeOutline = []; var portalConflicts = []; var portalFailure = false; var portalOutOfBounds = false; +var cycle = false; +var cycleID = -1; var tileSize = 34; var cachedTileSize = localStorage.getItem("cachedTileSize"); @@ -609,7 +611,9 @@ document.addEventListener("keydown", function (event) { case "M".charCodeAt(0): if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(TRELLIS); break; } - case 13: //return + case "N".charCodeAt(0): + if (modifierMask === 0) { cycle = true; cycleID++; render(); break; } + case 13: // return if (modifierMask === 0) { toggleTheme(); break; } case 32: // spacebar case 9: // tab @@ -1949,6 +1953,9 @@ function showEditorChanged() { function move(dr, dc) { portalOutOfBounds = false; portalFailure = false; + cycle = false; + cycleID = -1; + if (!isAlive()) return; animationQueue = []; animationQueueCursor = 0; @@ -2308,21 +2315,26 @@ function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations } function activatePortal(portalLocations, portalLocation, animations, changeLog) { - postPortalSnakeOutline = []; - portalConflicts = []; var otherPortalLocation = portalLocations[1 - portalLocations.indexOf(portalLocation)]; var portalRowcol = getRowcol(level, portalLocation); var otherPortalRowcol = getRowcol(level, otherPortalLocation); var delta = { r: otherPortalRowcol.r - portalRowcol.r, c: otherPortalRowcol.c - portalRowcol.c }; var object = findObjectAtLocation(portalLocation); + var objectLength = object.locations.length; var newLocations = []; - for (var i = 0; i < object.locations.length; i++) { + for (var i = 0; i < objectLength; i++) { var rowcol = getRowcol(level, object.locations[i]); var r = rowcol.r + delta.r; var c = rowcol.c + delta.c; + + var outlineID = Math.floor(postPortalSnakeOutline.length / objectLength); if (r >= 0 && c >= 0) { - postPortalSnakeOutline[i] = { r: r, c: c }; + postPortalSnakeOutline.push({ + id: outlineID, + r: r, + c: c, + }); newLocations.push(getLocation(level, r, c)); } if (!isInBounds(level, r, c)) return "outside"; // out of bounds @@ -4597,50 +4609,69 @@ function render() { } function drawSnakeOutline(outline, conflicts) { + context.fillStyle = "rgba(0,0,0,.2)"; + context.font = "50pt Impact"; + var textString = "Press N to cycle through diagrams"; + var textWidth = context.measureText(textString).width; + context.fillText(textString, (canvas.width / 2) - (textWidth / 2), 80); + + var maxID = 0; + for (var i = 0; i < outline.length; i++) { + maxID = outline[i].id; + } + var buffer = document.createElement("canvas"); buffer.width = canvas.width; buffer.height = canvas.height; var localContext = buffer.getContext("2d"); - localContext.strokeStyle = "white"; - localContext.lineWidth = tileSize / 6; + if (cycle) { + context.fillStyle = "rgba(0, 0, 0, 0.8)"; + context.fillRect(0, 0, canvas.width, canvas.height); + } for (var i = 0; i < outline.length; i++) { - var c = outline[i].c; - var r = outline[i].r; - localContext.beginPath(); - localContext.moveTo((c + .35) * tileSize, r * tileSize); - localContext.lineTo((c + .65) * tileSize, r * tileSize); - localContext.moveTo((c + .9) * tileSize, r * tileSize); - localContext.arcTo((c + 1) * tileSize, r * tileSize, (c + 1) * tileSize, (r + .1) * tileSize, tileSize / 6); - localContext.moveTo((c + 1) * tileSize, (r + .35) * tileSize); - localContext.lineTo((c + 1) * tileSize, (r + .65) * tileSize); - localContext.moveTo((c + 1) * tileSize, (r + .9) * tileSize); - localContext.arcTo((c + 1) * tileSize, (r + 1) * tileSize, (c + .9) * tileSize, (r + 1) * tileSize, tileSize / 6); - localContext.moveTo((c + .65) * tileSize, (r + 1) * tileSize); - localContext.lineTo((c + .35) * tileSize, (r + 1) * tileSize); - localContext.moveTo((c + .1) * tileSize, (r + 1) * tileSize); - localContext.arcTo(c * tileSize, (r + 1) * tileSize, c * tileSize, (r + .9) * tileSize, tileSize / 6); - localContext.moveTo(c * tileSize, (r + .65) * tileSize); - localContext.lineTo(c * tileSize, (r + .35) * tileSize); - localContext.moveTo(c * tileSize, (r + .1) * tileSize); - localContext.arcTo(c * tileSize, r * tileSize, (c + .1) * tileSize, r * tileSize, tileSize / 6); - localContext.stroke(); - //roundRect(localContext, outline[i].c * tileSize, outline[i].r * tileSize, tileSize, tileSize, 5, false, true); - } - - localContext.strokeStyle = "red"; - localContext.lineWidth = tileSize / 2.8; - for (var i = 0; i < conflicts.length; i++) { - var c = conflicts[i].c; - var r = conflicts[i].r; - localContext.beginPath(); - localContext.moveTo((c - .12) * tileSize, (r - .12) * tileSize); - localContext.lineTo((c + 1.12) * tileSize, (r + 1.12) * tileSize); - localContext.moveTo((c + 1.12) * tileSize, (r - .12) * tileSize); - localContext.lineTo((c - .12) * tileSize, (r + 1.12) * tileSize); - localContext.stroke(); + if (!(cycle && outline[i].id != cycleID)) { + localContext.strokeStyle = "white"; + localContext.lineWidth = tileSize / 6; + var c = outline[i].c; + var r = outline[i].r; + localContext.beginPath(); + localContext.moveTo((c + .35) * tileSize, r * tileSize); + localContext.lineTo((c + .65) * tileSize, r * tileSize); + localContext.moveTo((c + .9) * tileSize, r * tileSize); + localContext.arcTo((c + 1) * tileSize, r * tileSize, (c + 1) * tileSize, (r + .1) * tileSize, tileSize / 6); + localContext.moveTo((c + 1) * tileSize, (r + .35) * tileSize); + localContext.lineTo((c + 1) * tileSize, (r + .65) * tileSize); + localContext.moveTo((c + 1) * tileSize, (r + .9) * tileSize); + localContext.arcTo((c + 1) * tileSize, (r + 1) * tileSize, (c + .9) * tileSize, (r + 1) * tileSize, tileSize / 6); + localContext.moveTo((c + .65) * tileSize, (r + 1) * tileSize); + localContext.lineTo((c + .35) * tileSize, (r + 1) * tileSize); + localContext.moveTo((c + .1) * tileSize, (r + 1) * tileSize); + localContext.arcTo(c * tileSize, (r + 1) * tileSize, c * tileSize, (r + .9) * tileSize, tileSize / 6); + localContext.moveTo(c * tileSize, (r + .65) * tileSize); + localContext.lineTo(c * tileSize, (r + .35) * tileSize); + localContext.moveTo(c * tileSize, (r + .1) * tileSize); + localContext.arcTo(c * tileSize, r * tileSize, (c + .1) * tileSize, r * tileSize, tileSize / 6); + localContext.stroke(); + + for (var j = 0; j < conflicts.length; j++) { + if (conflicts[j].c === c && conflicts[j].r === r) { + c = conflicts[j].c; + r = conflicts[j].r; + localContext.strokeStyle = "red"; + localContext.lineWidth = tileSize / 2.8; + localContext.beginPath(); + localContext.moveTo((c - .12) * tileSize, (r - .12) * tileSize); + localContext.lineTo((c + 1.12) * tileSize, (r + 1.12) * tileSize); + localContext.moveTo((c + 1.12) * tileSize, (r - .12) * tileSize); + localContext.lineTo((c - .12) * tileSize, (r + 1.12) * tileSize); + localContext.stroke(); + } + } + } } + if (cycleID > maxID) cycleID = -1; context.save(); context.globalAlpha = 1; context.drawImage(buffer, 0, 0); From 768a3a5f283b2bb0ddf569019f6da0806479e2cc Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 14:32:21 -0500 Subject: [PATCH 374/577] Update Main.js --- Main.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Main.js b/Main.js index 5d997a9f..45c62755 100644 --- a/Main.js +++ b/Main.js @@ -1951,6 +1951,8 @@ function showEditorChanged() { } function move(dr, dc) { + postPortalSnakeOutline = []; + portalConflicts = []; portalOutOfBounds = false; portalFailure = false; cycle = false; From 55238f034bc1907f2221a58a29255de14d0dd50c Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 18:07:23 -0500 Subject: [PATCH 375/577] Update Editor.css --- Editor.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Editor.css b/Editor.css index 308d236e..73934e5b 100644 --- a/Editor.css +++ b/Editor.css @@ -282,3 +282,8 @@ canvas{ #fitButton:active{ transform: scale(.9); } + +#paradoxDiv{ + background: #f88; + text-align: center; +} From 0c1ceb04cbd3640c6674a2719773c2952fd64c60 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 18:07:36 -0500 Subject: [PATCH 376/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index 19ff88f5..80b060e6 100644 --- a/Framework.html +++ b/Framework.html @@ -129,7 +129,7 @@ -
    +
    Standard Level
    contains only original Snakebird elements


    From 44acddb1b8fe22c3183cd97583ebe7619e89e6d2 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 18:07:43 -0500 Subject: [PATCH 377/577] Update Main.js --- Main.js | 45 ++++++++++++++++++++++++++++----------------- 1 file changed, 28 insertions(+), 17 deletions(-) diff --git a/Main.js b/Main.js index 45c62755..5de9a9aa 100644 --- a/Main.js +++ b/Main.js @@ -4613,10 +4613,10 @@ function render() { function drawSnakeOutline(outline, conflicts) { context.fillStyle = "rgba(0,0,0,.2)"; context.font = "50pt Impact"; - var textString = "Press N to cycle through diagrams"; - var textWidth = context.measureText(textString).width; - context.fillText(textString, (canvas.width / 2) - (textWidth / 2), 80); + var textString = "Press the / (forward slash) key to cycle through diagrams"; + document.getElementById("paradoxDiv").innerHTML = textString; + var xSpots = []; var maxID = 0; for (var i = 0; i < outline.length; i++) { maxID = outline[i].id; @@ -4627,10 +4627,6 @@ function render() { buffer.height = canvas.height; var localContext = buffer.getContext("2d"); - if (cycle) { - context.fillStyle = "rgba(0, 0, 0, 0.8)"; - context.fillRect(0, 0, canvas.width, canvas.height); - } for (var i = 0; i < outline.length; i++) { if (!(cycle && outline[i].id != cycleID)) { localContext.strokeStyle = "white"; @@ -4658,20 +4654,26 @@ function render() { for (var j = 0; j < conflicts.length; j++) { if (conflicts[j].c === c && conflicts[j].r === r) { - c = conflicts[j].c; - r = conflicts[j].r; - localContext.strokeStyle = "red"; - localContext.lineWidth = tileSize / 2.8; - localContext.beginPath(); - localContext.moveTo((c - .12) * tileSize, (r - .12) * tileSize); - localContext.lineTo((c + 1.12) * tileSize, (r + 1.12) * tileSize); - localContext.moveTo((c + 1.12) * tileSize, (r - .12) * tileSize); - localContext.lineTo((c - .12) * tileSize, (r + 1.12) * tileSize); - localContext.stroke(); + xSpots.push({ + c: conflicts[j].c, + r: conflicts[j].r + }); } } } } + for (var i = 0; i < xSpots.length; i++) { + c = xSpots[i].c; + r = xSpots[i].r; + localContext.strokeStyle = "red"; + localContext.lineWidth = tileSize / 2.8; + localContext.beginPath(); + localContext.moveTo((c - .12) * tileSize, (r - .12) * tileSize); + localContext.lineTo((c + 1.12) * tileSize, (r + 1.12) * tileSize); + localContext.moveTo((c + 1.12) * tileSize, (r - .12) * tileSize); + localContext.lineTo((c - .12) * tileSize, (r + 1.12) * tileSize); + localContext.stroke(); + } if (cycleID > maxID) cycleID = -1; context.save(); @@ -4679,6 +4681,15 @@ function render() { context.drawImage(buffer, 0, 0); context.restore(); } + + function fitTextOnCanvas(text, fontface, yPosition) { + var fontsize = 50; + do { + fontsize--; + context.font = fontsize + "px " + fontface; + } while (context.measureText(text).width > canvas.width) + context.fillText(text, 0, yPosition); + } } function findAnimation(animationTypes, objectId) { From 78f253c557e60672d69cd6c871c33fd4c0bd8e88 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 18:09:30 -0500 Subject: [PATCH 378/577] Update Main.js --- Main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Main.js b/Main.js index 5de9a9aa..68e49892 100644 --- a/Main.js +++ b/Main.js @@ -611,7 +611,7 @@ document.addEventListener("keydown", function (event) { case "M".charCodeAt(0): if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(TRELLIS); break; } - case "N".charCodeAt(0): + case 191: if (modifierMask === 0) { cycle = true; cycleID++; render(); break; } case 13: // return if (modifierMask === 0) { toggleTheme(); break; } From 30fa94b927f11b6d50d796df6f7a864427ff7375 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 21:08:59 -0500 Subject: [PATCH 379/577] Update Main.js --- Main.js | 112 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 85 insertions(+), 27 deletions(-) diff --git a/Main.js b/Main.js index 68e49892..2007c1cf 100644 --- a/Main.js +++ b/Main.js @@ -3,6 +3,9 @@ if (typeof VERSION !== "undefined") { document.getElementById("versionSpan").innerHTML = '' + VERSION.tag + ''; } + +var rng = new Math.seedrandom('hello.'); + /*$(document).ready(function() { var fruits1 = getObjectsOfType(FRUIT); $(fruits1[0]).jqFloat({ @@ -54,6 +57,7 @@ var portalFailure = false; var portalOutOfBounds = false; var cycle = false; var cycleID = -1; +var multiDiagrams = false; var tileSize = 34; var cachedTileSize = localStorage.getItem("cachedTileSize"); @@ -206,8 +210,23 @@ function parseLevel(string) { skipWhitespace(); } - if (enhanced) document.getElementById("levelType").innerHTML = "Enhanced Level
    contains new elements not present in the original Snakebird game"; - else document.getElementById("levelType").innerHTML = "Standard Level
    contains only original Snakebird elements"; + //describe level type + if (enhanced) { + document.getElementById("levelType").innerHTML = "Enhanced Level
    contains new elements not present in the original Snakebird game"; + document.getElementById("additions").style.color = "transparent"; + if (tileCounter === 0) { + document.getElementById("additions").innerHTML = "*all initial enhanced elements have been removed but the level is not saved*"; + document.getElementById("additions").style.color = "#f88"; + } + } + else { + document.getElementById("levelType").innerHTML = "Standard Level
    contains only original Snakebird elements"; + if (tileCounter > 0) { + document.getElementById("additions").innerHTML = "*enhanced elements have been added to this level but the level is not saved*"; + document.getElementById("additions").style.color = "#f88"; + } + else document.getElementById("additions").style.color = "transparent"; + } for (var i = 0; i < upconvertedObjects.length; i++) { level.objects.push(upconvertedObjects[i]); @@ -407,6 +426,7 @@ function saveLevel() { unmoveStuff.redoStack = []; editorHasBeenTouched = false; undoStuffChanged(unmoveStuff); + location.reload(); } function saveReplay() { @@ -612,7 +632,7 @@ document.addEventListener("keydown", function (event) { if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(TRELLIS); break; } case 191: - if (modifierMask === 0) { cycle = true; cycleID++; render(); break; } + if (modifierMask === 0) { if (multiDiagrams) { cycle = true; cycleID++; render(); } break; } case 13: // return if (modifierMask === 0) { toggleTheme(); break; } case 32: // spacebar @@ -1951,12 +1971,14 @@ function showEditorChanged() { } function move(dr, dc) { + document.getElementById("cycleDiv").innerHTML = ""; postPortalSnakeOutline = []; portalConflicts = []; portalOutOfBounds = false; portalFailure = false; cycle = false; cycleID = -1; + multiDiagrams = false; if (!isAlive()) return; animationQueue = []; @@ -2084,6 +2106,9 @@ function move(dr, dc) { } else if (result === "outside") { portalFailure = true; portalOutOfBounds = true; + } else if (result === "blockedBySnake") { + portalFailure = false; + portalOutOfBounds = false; } portalActivationLocations = []; } @@ -2342,11 +2367,19 @@ function activatePortal(portalLocations, portalLocation, animations, changeLog) if (!isInBounds(level, r, c)) return "outside"; // out of bounds } + var blockedBySnake = false; for (var i = 0; i < newLocations.length; i++) { var location = newLocations[i]; if (!isTileCodeAir(object, null, level.map[location], 0, 0)) portalConflicts.push(getRowcol(level, location)); // blocked by tile var otherObject = findObjectAtLocation(location); - if (otherObject != null && otherObject !== object) portalConflicts.push(getRowcol(level, location)); // blocked by object + if (otherObject != null && otherObject !== object) { + if (otherObject.type !== SNAKE) portalConflicts.push(getRowcol(level, location)); // blocked by object + else blockedBySnake = true; + } + } + if (blockedBySnake) { + portalConflicts = []; + return "blockedBySnake"; } if (portalConflicts.length > 0) return "blocked"; @@ -2453,6 +2486,14 @@ function getPortalLocations() { } return result; } +function isSnakeOnPortal() { + var portalLocations = getPortalLocations(); + if (portalLocations.length !== 2) return false; + var o1 = findObjectAtLocation(portalLocations[0]); + var o2 = findObjectAtLocation(portalLocations[1]); + if ((o1 != null && o1.type === SNAKE) || (o2 != null && o2.type === SNAKE)) return true; + return false; +} function countSnakes() { return getSnakes().length; } @@ -2887,8 +2928,9 @@ function render() { drawQuarterPie(r, c, radiusFactor, snakeColors[3], 3); break; case PORTAL: + var whitePortal = isSnakeOnPortal(); context.save(); - if (activePortalLocations.indexOf(location) !== -1) { + if (!whitePortal && activePortalLocations.indexOf(location) !== -1) { context.fillStyle = "black"; context.strokeStyle = "purple"; context.shadowColor = "purple"; @@ -2900,6 +2942,18 @@ function render() { context.fill(); context.stroke(); } + else if (whitePortal) { + context.fillStyle = "white"; + context.strokeStyle = "purple"; + context.shadowColor = "purple"; + context.shadowBlur = 5; + context.lineWidth = 3; + context.beginPath(); + context.arc(c * tileSize + tileSize / 2, r * tileSize + tileSize / 2, tileSize / 3, 0, 2 * Math.PI); + context.closePath(); + context.fill(); + context.stroke(); + } else drawCircle(r, c, 1, "#999"); context.restore(); break; @@ -3162,7 +3216,7 @@ function render() { var x2 = (isOccupied(1, 0)) ? 0 : .05; var platformColors = ["#ffcccc", "#ffe0cc", "#ffffcc", "#e6ffe6", "#e6e6ff"]; - for (var i = 0; i < 3; i++) { + for (var i = 0; i < 5; i++) { var j = (i != 0) ? i - 1 : 0; context.beginPath(); context.moveTo(c * tileSize + tileSize * (i * x1), r * tileSize + tileSize * (.05 + (.1 * i) - (j * .02))); @@ -3548,22 +3602,34 @@ function render() { else if (!isOccupied(0, -1) && !isOccupied(1, 0) && !isOccupied(0, 1) && !isOccupied(-1, 0)) roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 10, true, false); else roundRect(context, c * tileSize, r * tileSize, tileSize, tileSize, 0, true, false); - /*var randomSpot = Math.floor(Math.random() * 5); //random spots on dirt - var randomColor = Math.floor(Math.random() * 5); + /* var randomSpot = Math.floor(rng() * 5); //random spots on dirt + var randomColor = Math.floor(rng() * 5); context.beginPath(); - switch(randomSpot){ + switch (randomSpot) { + case 0: + context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, 5, 0, 2 * Math.PI); break; + case 1: + context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, 4, 0, 2 * Math.PI); break; + case 2: + context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, 3, 0, 2 * Math.PI); break; + case 3: + context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, 2, 0, 2 * Math.PI); break; + case 4: + context.arc(c * tileSize + tileSize * .5, r * tileSize + tileSize * .5, 1, 0, 2 * Math.PI); break; + } + switch (randomColor) { case 0: - context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 5, 0, 2*Math.PI); + context.fillStyle = "white"; break; case 1: - context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 4, 0, 2*Math.PI); + context.fillStyle = "red"; break; case 2: - context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 3, 0, 2*Math.PI); + context.fillStyle = "blue"; break; case 3: - context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 2, 0, 2*Math.PI); + context.fillStyle = "yellow"; break; case 4: - context.arc(c*tileSize+tileSize*.5,r*tileSize+tileSize*.5, 1, 0, 2*Math.PI); + context.fillStyle = "black"; break; } - context.stroke();*/ + context.fill(); */ } function drawCurves(r, c, adjacentTiles) { @@ -4064,12 +4130,6 @@ function render() { context.arc(cx, cy, radiusFactor * tileSize / 2, quadrant * Math.PI / 2, (quadrant + 1) * Math.PI / 2); context.fill(); } - function drawDiamond(r, c, fillStyle) { - var x = c * tileSize; - var y = r * tileSize; - context.fillStyle = fillStyle; - roundRect(context, x, y, tileSize, tileSize, 10, true, false); - } function drawCircle(r, c, radiusFactor, fillStyle) { context.fillStyle = fillStyle; context.beginPath(); @@ -4611,16 +4671,14 @@ function render() { } function drawSnakeOutline(outline, conflicts) { - context.fillStyle = "rgba(0,0,0,.2)"; - context.font = "50pt Impact"; - var textString = "Press the / (forward slash) key to cycle through diagrams"; - document.getElementById("paradoxDiv").innerHTML = textString; + if (multiDiagrams) document.getElementById("cycleDiv").innerHTML = "Press the / (forward slash) key to cycle through diagrams"; var xSpots = []; - var maxID = 0; + var maxID = -1; for (var i = 0; i < outline.length; i++) { maxID = outline[i].id; } + if (maxID > 0) multiDiagrams = true; var buffer = document.createElement("canvas"); buffer.width = canvas.width; @@ -4675,7 +4733,7 @@ function render() { localContext.stroke(); } - if (cycleID > maxID) cycleID = -1; + if (cycleID > maxID) cycleID = 0; context.save(); context.globalAlpha = 1; context.drawImage(buffer, 0, 0); From c2792ee619bcbba3d81eefd61400d26c3e1bd5f9 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 21:09:08 -0500 Subject: [PATCH 380/577] Update Editor.css --- Editor.css | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Editor.css b/Editor.css index 73934e5b..82d63fc8 100644 --- a/Editor.css +++ b/Editor.css @@ -115,17 +115,12 @@ button:active:enabled{ font-family: Arial; font-size: 12pt; color:slateblue; - margin: 10px 0 10px 0; + margin: 10px 0 1px 0; display: inline-block; vertical-align: top; font-weight: 900; } -#levelType span{ - font-size: 6pt; - font-weight: 100; -} - canvas{ border: 2px solid black; } @@ -287,3 +282,19 @@ canvas{ background: #f88; text-align: center; } + +#cycleDiv{ + background: yellow; + text-align: center; +} + +#additions{ + font-family: Arial; + color: transparent; + font-size: 8pt; +} + +#levelTypeSpan{ + font-size: 8pt; + font-weight: 100; +} From 0f2c7e8a7d5c0e50ae0f6f250e10c5ac34a90b77 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 21:09:16 -0500 Subject: [PATCH 381/577] Update Framework.html --- Framework.html | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Framework.html b/Framework.html index 80b060e6..607e4a32 100644 --- a/Framework.html +++ b/Framework.html @@ -8,8 +8,10 @@ + + + - @@ -130,9 +132,11 @@
    +
    -
    Standard Level
    contains only original Snakebird elements


    +
    Standard Level
    contains only original Snakebird elements
    +
    *

    Game Controls

    use the arrows or WASD keys on your keyboard to move, or use the buttons below
    @@ -162,9 +166,9 @@
    Options

    FIT
    Level Size
    +


    -

    From 1d24a6eaae2e6701a83f178df5c686cc4b5dbd27 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 21:19:43 -0500 Subject: [PATCH 382/577] Update Main.js --- Main.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Main.js b/Main.js index 2007c1cf..c11f95e2 100644 --- a/Main.js +++ b/Main.js @@ -4013,17 +4013,14 @@ function render() { function drawBolt(r, c) { context.strokeStyle = spikeColors[3]; context.beginPath(); - context.arc(c * tileSize + (tileSize * .55), r * tileSize + (tileSize * .45), 4, -.7 * Math.PI, .2 * Math.PI); - context.lineTo(c * tileSize + (tileSize * .45), r * tileSize + (tileSize * .35)); + context.arc((c + .52) * tileSize, (r + .47) * tileSize, tileSize / 8, -.7 * Math.PI, .18 * Math.PI); context.closePath(); context.fillStyle = spikeColors[3]; context.fill(); context.stroke(); context.beginPath(); - context.moveTo(c * tileSize + (tileSize * .43), r * tileSize + (tileSize * .47)); - context.arc(c * tileSize + (tileSize * .48), r * tileSize + (tileSize * .52), 4, .2 * Math.PI, -.75 * Math.PI); - //context.lineTo(c*tileSize+(tileSize*.4),r*tileSize+(tileSize*.6)); + context.arc((c + .48) * tileSize, (r + .52) * tileSize, tileSize / 9, .2 * Math.PI, -.75 * Math.PI); context.closePath(); context.fillStyle = spikeColors[3]; context.fill(); From 13c88bff83e66ea699a3431970f3375f3bfe1480 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 21:26:37 -0500 Subject: [PATCH 383/577] Update Framework.html --- Framework.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Framework.html b/Framework.html index 607e4a32..3b7a6478 100644 --- a/Framework.html +++ b/Framework.html @@ -165,7 +165,7 @@
    Options

    -
    FIT
    Level Size
    +
    FIT
    Level Size



    From 2c1916483771e9b4fa1895e9ee5aaa943987ce06 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 21:26:45 -0500 Subject: [PATCH 384/577] Update Main.js --- Main.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Main.js b/Main.js index c11f95e2..712ff509 100644 --- a/Main.js +++ b/Main.js @@ -588,7 +588,6 @@ document.addEventListener("keydown", function (event) { if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(FRUIT); break; } if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(POISON_FRUIT); break; } if (!persistentState.showEditor && modifierMask === 0) { fitCanvas(); break; } - if (persistentState.showEditor && modifierMask === CTRL) { fitCanvas(); break; } return; case "D".charCodeAt(0): if (!persistentState.showEditor && modifierMask === 0) { move(0, 1); break; } @@ -631,6 +630,8 @@ document.addEventListener("keydown", function (event) { case "M".charCodeAt(0): if (persistentState.showEditor && modifierMask === 0) { setPaintBrushTileCode(PLATFORM); break; } if (persistentState.showEditor && modifierMask === SHIFT) { setPaintBrushTileCode(TRELLIS); break; } + case 192: + if (modifierMask === 0) { fitCanvas(); break; } case 191: if (modifierMask === 0) { if (multiDiagrams) { cycle = true; cycleID++; render(); } break; } case 13: // return @@ -1944,8 +1945,8 @@ var themes = [ //name, background, material, surface, curlyOutline, blockColors //["sky",], ["Spring", bg1, "#976537", "#95ff45", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], ["Winter", bg1, "#30455B", "white", true, snakeColors1, blockColors1, spikeColors1, fruitColors1, "green", textStyle1, experimentalColors1], - ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], ["Summer", bg2, "#734d26", "#009933", true, snakeColors3, blockColors3, spikeColors1, fruitColors1, "green", textStyle3, experimentalColors2], + ["Classic", "#8888ff", "#844204", "#282", false, snakeColors2, blockColors1, spikeColors3, fruitColors1, "green", textStyle4, experimentalColors1], ["Dream", bg3, "#00aaff", "#ffb3ec", true, snakeColors1, blockColors4, spikeColors1, fruitColors2, "white", textStyle2, experimentalColors2], ["Midnight Rainbow", bg4, "black", "rainbow", false, snakeColors1, blockColors5, spikeColors2, "white", "white", textStyle1, experimentalColors1] ]; From 540e3c35b3c9cb055a5e81a4ac2724566e1b94b2 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 23:33:57 -0500 Subject: [PATCH 385/577] Update Main.js --- Main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Main.js b/Main.js index 712ff509..d1dc117b 100644 --- a/Main.js +++ b/Main.js @@ -1961,7 +1961,7 @@ document.getElementById("themeButton").innerHTML = "Theme: " + themeName + "< function showEditorChanged() { document.getElementById("showHideEditor").textContent = (persistentState.showEditor ? "Hide" : "Show") + " Editor"; ["editorDiv", "editorPane"].forEach(function (id) { - document.getElementById(id).style.display = persistentState.showEditor ? "block" : "none"; + document.getElementById(id).style.display = persistentState.showEditor ? "inline-block" : "none"; }); document.getElementById("wasdSpan").textContent = persistentState.showEditor ? "" : " or WASD"; @@ -2797,7 +2797,7 @@ function render() { } } - if (portalFailure) { + if (portalFailure && countSnakes() != 0) { drawSnakeOutline(postPortalSnakeOutline, portalConflicts); //failed portal diagram if (portalOutOfBounds) { context.strokeStyle = "rgba(255,0,0,.5)"; From 9f7cedca3600d6d4182635a41d6cf463a9bd7e37 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 23:34:14 -0500 Subject: [PATCH 386/577] Update Editor.css --- Editor.css | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/Editor.css b/Editor.css index 82d63fc8..b42600c0 100644 --- a/Editor.css +++ b/Editor.css @@ -187,8 +187,7 @@ canvas{ } #bigButtonButton{ - position: absolute; - left: 10; + display: block; font-size: 20pt; padding: 10px; } @@ -292,9 +291,29 @@ canvas{ font-family: Arial; color: transparent; font-size: 8pt; + margin-top: 1px; } #levelTypeSpan{ font-size: 8pt; font-weight: 100; } + +#editorDiv{ + width: 100%; + text-align: center; +} + +#shareLink{ + padding-right: 5px; + display: table-cell; + font-size: 10pt; +} + +#shareLinkTextbox{ + padding: 5px; + display: table-cell; + border-radius: 2px; + border: 1px solid black; + background-color:white; +} From f394c821b6a78ff2d40d797bda47195780d13a8d Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Sat, 7 Mar 2020 23:34:27 -0500 Subject: [PATCH 387/577] Update Framework.html --- Framework.html | 79 ++++++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 35 deletions(-) diff --git a/Framework.html b/Framework.html index 3b7a6478..59db8fb1 100644 --- a/Framework.html +++ b/Framework.html @@ -21,23 +21,23 @@ ←Snakefall Redesign - + - - + + Edits: 0+0 Controls - +
    - +
    - - - + + +
    @@ -46,8 +46,8 @@ Physics - - + + @@ -60,7 +60,7 @@

    W

    S
    -

    Shift  E
    +

    Shift  E

    P
    @@ -68,22 +68,22 @@ Kinetic -

    Shift  S
    +

    Shift  S

    F

    B
    - Experimental Elements + Enhanced Elements --------------------------- Kinetic -

    Shift  F
    +

    Shift  F

    C
    -

    Shift  B
    +

    Shift  B
    @@ -91,7 +91,7 @@

    M
    -

    Shift  M

    +

    Shift  M

    @@ -107,7 +107,7 @@

    T
    -

    Shift  T
    +

    Shift  T
    @@ -115,7 +115,7 @@

    X
    -

    Shift  X
    +

    Shift  X
    @@ -123,7 +123,7 @@

    L
    -

    Shift  L
    +

    Shift  L
    @@ -133,7 +133,6 @@
    -
    Standard Level
    contains only original Snakebird elements
    *

    @@ -141,7 +140,7 @@
    Game Controls

    use the arrows or WASD keys on your keyboard to move, or use the buttons below
    -
    +
    @@ -155,36 +154,46 @@
    Progress Tracking

    - + Moves: 0+0 -
    - -

    +
    + +

    Options

    -
    FIT
    Level Size
    -

    +
    FIT
    Level Size
    + +

    +
    - +


    +
    - +

    +

    a?c2j5rMj`ftK0e2cu46JK>7v!cF>+mPS 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 From e3e999c14f4917ff1b4e77b033a58383cd31a408 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:54 -0500 Subject: [PATCH 210/577] Delete Pear.png --- Snakebird Images/Pear.png | Bin 24856 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/Pear.png diff --git a/Snakebird Images/Pear.png b/Snakebird Images/Pear.png deleted file mode 100644 index a7751e5dd3d430e289019a493e19a7cba163f424..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 24856 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 W?;h$d6!^!3SzDcVIF&g1#{L6Txborv From dffa9eb3a2836f7402f8929b2d03efac615951b0 Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:26:55 -0500 Subject: [PATCH 211/577] Delete Peach.png --- Snakebird Images/Peach.png | Bin 22131 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/Peach.png diff --git a/Snakebird Images/Peach.png b/Snakebird Images/Peach.png deleted file mode 100644 index 8b98509b0eb6f9e4eba68bc3643dfa5061e165fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22131 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 Date: Mon, 10 Feb 2020 15:26:57 -0500 Subject: [PATCH 212/577] Delete Banana.png --- Snakebird Images/Banana.png | Bin 18537 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 Snakebird Images/Banana.png diff --git a/Snakebird Images/Banana.png b/Snakebird Images/Banana.png deleted file mode 100644 index a24a6dc7cc46511994aa1bf9a698dbeeccbb806c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18537 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 Date: Mon, 10 Feb 2020 15:35:21 -0500 Subject: [PATCH 213/577] Update Format.css --- Format.css | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Format.css b/Format.css index 08658aed..7afd11f0 100644 --- a/Format.css +++ b/Format.css @@ -95,12 +95,12 @@ td a{ } #buttonContainer{ - width: 50%; - margin-left: 25%; - margin-right: 25%; + width: 36%; + margin-left: 32%; + margin-right: 32%; text-align: center; color: white; - margin-bottom: 40px; + margin-bottom: 60px; } .topButton{ @@ -110,11 +110,11 @@ td a{ border-radius: 10px; color: white; background-color: #730c39; - width: 25%; + width: 40%; margin: 10px; border: 2px solid black; - text-transform:uppercase; - font-size: 14px; + text-transform: uppercase; + font-size: 12pt; } .topButton:active { @@ -184,7 +184,7 @@ td a{ height: 100px; width: 300px; margin: auto; - background-color: rgba(0,0,0,.8); + background-color: darkslategray; position: absolute; left: 0; right: 0; From a04fed73bbbcd381709b56faa4ac4a633a6e9fde Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:41:57 -0500 Subject: [PATCH 214/577] Update Main.js --- Main.js | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/Main.js b/Main.js index ab8d344a..e3555bcf 100644 --- a/Main.js +++ b/Main.js @@ -32,23 +32,6 @@ var ONEWAYWALLR = "r".charCodeAt(0); var FOAM = "f".charCodeAt(0); var OPENGATE = "o".charCodeAt(0); var CLOSEDGATE = "c".charCodeAt(0); - -// tile codes -/*var SPACE = 0; -var WALL = 1; -var SPIKE = 2; -var FRUIT_v0 = 3; // legacy -var EXIT = 4; -var PORTAL = 5; -var PLATFORM = 6; -var WOODPLATFORM = 7; -var ONEWAYWALLU = 8; -var ONEWAYWALLD = 9; -var ONEWAYWALLL = 10; -var ONEWAYWALLR = 11; -var OPENGATE = 12; -var CLOSEDGATE = 13; -var FOAM = 14;*/ var validTileCodes = [SPACE, WALL, SPIKE, EXIT, PORTAL, PLATFORM, WOODPLATFORM, ONEWAYWALLU, ONEWAYWALLD, ONEWAYWALLL, ONEWAYWALLR, OPENGATE, CLOSEDGATE, FOAM]; // object types @@ -2080,6 +2063,10 @@ function moveObjects(objects, dr, dc, portalLocations, portalActivationLocations var oldPortals = getSetIntersection(portalLocations, object.locations); for (var i = 0; i < object.locations.length; i++) { object.locations[i] = offsetLocation(object.locations[i], dr, dc); + if (level.map[object.locations[i]] == FOAM) + { + paintTileAtLocation(object.locations[i], SPACE, changeLog); + } } changeLog.push([object.type, object.id, oldState, serializeObjectState(object)]); animations.push([ From 7102d61b478a9fea3abfc6e8a2d66c37fc6f154a Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 15:52:10 -0500 Subject: [PATCH 215/577] Update index.html --- index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.html b/index.html index dd627ee0..6b597c0e 100644 --- a/index.html +++ b/index.html @@ -569,7 +569,7 @@ - Bundók + Bundók Gooby From 94d91ac37c5a6c5565027b0f800faaf11c589a1e Mon Sep 17 00:00:00 2001 From: Gooby <34070642+jmdiamond3@users.noreply.github.com> Date: Mon, 10 Feb 2020 16:05:15 -0500 Subject: [PATCH 216/577] Update Framework.html --- Framework.html | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Framework.html b/Framework.html index 0bbb2281..8f7b9a4b 100644 --- a/Framework.html +++ b/Framework.html @@ -1,7 +1,7 @@ Snakefall Redesign - + @@ -84,11 +84,9 @@ -